使用 sqlalchemy 在刷新/提交时自动散列主键并使其持久化
Posted
技术标签:
【中文标题】使用 sqlalchemy 在刷新/提交时自动散列主键并使其持久化【英文标题】:Automatically hash primary key and make it persistent upon flush/commit with sqlalchemy 【发布时间】:2012-09-09 17:27:22 【问题描述】:我正在尝试在 sqlalchemy 中获取对象主键的哈希值。
class 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()
之后分配的。
但在刷新期间,对象状态的更改不会持久化。
唯一对我有用的解决方案是在第一次刷新之后延迟加载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 事件文档中遗漏了一些东西?
【问题讨论】:
【参考方案1】:这是 after_insert() 的好地方,因为这是第一次新生成的 PK 始终可用(它也不需要选择,但不确定您所说的“延迟加载用户。 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
)
【讨论】:
是否有一种优雅的方式将这些更改传播回新创建的对象? @zzzeek 如果使用 set_committed_value(object, "hash", myhash),可以在不触发历史的情况下设置值:docs.sqlalchemy.org/en/rel_0_7/orm/… 有没有其他方法可以直接使用docs.sqlalchemy.org/en/latest/core/…中的默认Context-Sensitive Default Functions
来生成hashid?或者只使用event.listens_for
来完成这项工作。我几乎找不到任何解决方案。
在插入之前有没有办法散列?在我看来,插入然后更新不是一个好方法,因为它是两个具有一个目标的操作以上是关于使用 sqlalchemy 在刷新/提交时自动散列主键并使其持久化的主要内容,如果未能解决你的问题,请参考以下文章