我使用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参数中没有使用其他字段的东西。
我希望我很清楚,因为我不是“天生的英语演讲者” 谢谢大家
答案 0 :(得分: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
对象中的更改是否正确钩。
答案 1 :(得分:5)
SQLAlchemy具有在默认(即onupdate)函数中使用其他列值的特殊机制:上下文敏感默认函数 http://docs.sqlalchemy.org/en/rel_0_7/core/schema.html#context-sensitive-default-functions:
关于默认情况的此上下文的典型用例 生成是为了访问要插入的其他值或 在行上更新。
正如Van指出的那样,您需要确保邮政编码是为Person定义的字段,或者您需要添加功能,以便获取与Person实例关联的邮政编码。
什么对我有用 - 常规功能,不受任何对象的约束。 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)
# ...
小心这个上下文参数 - 如果我没有使用相同的操作更新'postcode'值,在某些情况下上下文具有None字段的值时,我最终会遇到问题。
带有调试器的带有pydev的Eclipse帮助我查看了哪些信息作为上下文传递。答案 2 :(得分:0)
请谨慎使用此上下文参数-如果我不使用相同的操作更新“邮政编码”值,在某些情况下上下文具有“无”字段的值将导致一个问题。
@vvladymyrov提到他最终遇到的问题是,如果您使用的是未更新的字段值,则上下文将生成None。但是,您仍然需要计算另一个。
例如:
您具有firstName和lastName,这些名称将作为用户的输入。您还具有基于firstName和lastName计算的fullName。以下是您遵循的代码:
#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
现在让我们考虑一种情况,您想更新用户的lastName,并且在内部也应使用您可以实现的validateFullName函数来更新名称,但是如果您尝试执行以下操作,则需要警告:
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,您将获得上下文,但是在该上下文中。current_parameters的firstName将为None。 (由于您不更新firstName,因此如果需要,您将获得该值作为None,如果您可以打印(上下文。 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(),以便在上下文对象中获取该记录。
注意:我采用的方法可能不是有效的方法。如果我有任何错误,请指导我。我很高兴学习。