我想在sqlalchemy中获取对象主键的哈希值.
User类的示例类看起来像这样:
class User(base):
__tablename__ == 'users'
id = Column(Integer, primary_key=True)
hash = Column(String(38), unique=True)
并添加用户:
user = User()
session.add(user)
session.commit()
print user.id
我试图将散列过程挂钩到ORM事件中,因为主键是在session.flush()之后分配的.
但是在flush中,对对象状态的更改不会持久化.
对我来说唯一的解决方案是在第一次刷新和哈希之后延迟加载user.id,再次分配和刷新,最后提交.
class User(base):
...
@hybrid_property
def hash(self):
if not self.hash:
self.hash = hash_function(self.id)
return self.hash
这使我能够做到以下几点:
user = User()
session.add(user)
hash = user.hash
session.commit()
sqlalchemy启动UPDATE和user.hash并使其持久化.
但这似乎是一个糟糕的选择,例如如果有人忘记分配哈希(可能在创建对象的那一刻不需要哈希).
还有其他选择吗?
我真的更喜欢它自动哈希after_insert.
也许我在ORM事件文档中遗漏了一些东西?
最佳答案 这是after_insert()的一个好地方,因为这是第一次新生成的PK一直可用(它也不需要被选中,但不确定你的意思是“延迟加载user.id”,它应该被分配)你想要做的是直接发出UPDATE语句.这就是映射器级别刷新事件被赋予连接(而不是会话)的原因.
应该像这样简单:
@event.listens_for(User, "after_insert")
def update_hash(mapper, connection, target):
user_table = mapper.local_table
connection.execute(
user_table.update().
values(hash=hash_function(target.id)).
where(user_table.c.id==target.id)
)
如果你想让许多用户更有效率,你可以在after_flush()事件中做到这一点:
@event.listens_for(Session, "after_flush")
def update_hash(session, flush_context):
hashes = [
{"user_id":element.id, "hash":hash_function(element.id)}
for element in session.new if isinstance(element, User)
]
user_table = mapper.local_table
session.execute(
user_table.update().
values(hash=bind('hash')).
where(user_table.c.id==bind('user_id')),
hashes
)