2

我将 sqlalchemy 与金字塔框架一起使用,并且我想使用他的邮政编码将一个人链接到他的地理部门。所以我在定义department_id 列定义department_id 时尝试使用onupdate 参数。参见下面的代码:

from datetime import date
from emailing.models import Base, DBSession
from sqlalchemy import Column, Integer, Unicode, Text, DateTime, Sequence, Boolean, Date, UnicodeText, UniqueConstraint, Table, ForeignKey
from sqlalchemy.orm import scoped_session, sessionmaker, column_property, relationship, backref
from sqlalchemy.sql import func

class Person(Base):
    __tablename__ = u'person'
    id = Column(Integer, primary_key=True)

    firstName = Column(Unicode(255))
    lastName = Column(Unicode(255))

    created_at = Column(Date, default=func.now())
    updated_at = Column(Date, onupdate=func.now())

    department_id = Column(Integer(), ForeignKey('department.id'), onupdate=dep_id_from_postcode)
    department = relationship("Department", backref='persons')


    __table_args__ = (UniqueConstraint('firstName', 'lastName'), {})


    def dep_id_from_postcode(self):
        return int(self.postcode[:2]) 

在更新 updated_at 字段时工作正常,但对于 deparment_id 字段它告诉我:

NameError:未定义名称“dep_id_from_postcode”

我在这里找到了关于 python 执行函数的文档:http: //docs.sqlalchemy.org/en/latest/core/schema.html ?highlight=trigger#python-executed-functions 但没有在 onupdate 中使用另一个字段争论。

我希望我很清楚,因为我不是“天生的英语演讲者”谢谢大家

4

3 回答 3

7

在使用之前移动函数定义:

class Person(Base):
    # ...
    def dep_id_from_postcode(self):
        return int(self.postcode[:2])
    # ...
    department_id = Column(Integer(), ForeignKey('department.id'), onupdate=dep_id_from_postcode)
    # ...

真的postcode是直接在一个领域Person吗?因为如果不是,您可能需要完全不同的处理方式。例如,如果postcode是从primary_address关系派生的,则需要检查primary_address关系的添加/删除以及相关Address对象中的更改以进行正确的挂钩。

于 2012-06-21T10:36:45.277 回答
5

SQLAlchemy 具有在默认(即 onupdate)函数中使用其他列值的特殊机制,称为:Context-Sensitive Default Functions http://docs.sqlalchemy.org/en/rel_0_7/core/schema.html#context-sensitive-default-functions

与默认生成有关的此上下文的典型用例是可以访问在行上插入或更新的其他值。

正如 Van 指出的那样,您需要确保 postcode 是为 Person 定义的字段,否则您需要添加功能来处理获取与 Person 实例关联的 postcode。

什么对我有用 - 常规功能,不绑定到任何对象。SQLAlchemy 将在插入和/或更新时调用它,并使用“context”传递特殊参数 - 这不是您正在更新的实际对象。

所以对于你的例子,我会做这样的事情。

def dep_id_from_postcode(context):
    postcode = context.current_parameters['postcode']
    return int(postcode[:2])

class Person(Base):
    postcode = Column(String)
    # ...

    # ...
    department_id = Column(Integer(), ForeignKey('department.id'), onupdate=dep_id_from_postcode)
    # ...

小心这个上下文参数 - 如果我不使用相同的操作更新“邮政编码”值,那么在某些情况下,当上下文具有 None 字段的值时,我最终会遇到问题。

带有调试器的 pydev 的 Eclipse 帮助我查看了作为上下文传递的信息。

于 2012-06-22T20:27:59.817 回答
1

小心这个上下文参数 - 如果我不使用相同的操作更新“邮政编码”值,那么在某些情况下,当上下文具有 None 字段的值时,我最终会遇到问题。

正如@vvladymyrov 提到的那样,如果您使用未更新的字段值,他最终会遇到上下文将产生 None 的问题。但是,您仍然需要计算另一个。

例如:

您有 firstName 和 lastName 将被视为用户的输入。您还拥有根据名字和姓氏计算的全名。以下是您遵循的代码:

#The below code is the ERModel class in sqlalchemy
def calculateFullName(context):
    name = context.current_parameters['firstName'] + " " + context.current_parameters['lastName']
    return name

class User(Base):
    firstName= Column(String)
    lastName= Column(String)
    name= Column(String,default=calculateFullName,onupdate=calculateFullName)
    # ...
    # ...
# End of ER Model

现在让我们考虑一种情况,您想要更新用户的姓氏,并且在内部,名称也应该通过使用 calculateFullName 函数进行更新,您可以实现它,但如果您尝试执行以下操作,请注意:

user = session.query(User).filter(User.id=<id>).one() # Here you will get the specific user based on id.
user.lastName = "XXX" #This is the new value you want to be updated for the existing user.
session.update(user)
session.commit()

如前所述,上面将调用 calculateFullName 并且您将获得上下文,但在该 context.current_parameters 中,firstName 将为 None。(由于您没有更新 firstName,您将获得该值为 None,如果您愿意,您可以 print(context. dict ) 检查您得到的内容)。

因此,我为这类情况找到的解决方案(更新依赖于 2 列的列,其中只有一个列正在更新)使用会话查询 update() 函数,如下所示:

query = session.query(User).filter(User.id=<id>)  # This will return query object
query.update({"lastName"="XXX", "firstName"=query.one().__dict__.get("firstName")},syncronize_session=False)

当您更新 lastName 时,您需要 firstName 来计算名称。因此,您需要将 firstName 发送到上下文。由于您已经查询并将当前记录从数据库获取到内存,您可以使用它并将其发送到 query.update() 以便您将在上下文对象中获得它。

注意:我采取的方法可能不是有效的方法。如果我犯了任何错误,请指导我。我很高兴学习。

于 2019-06-24T01:41:37.400 回答