属性持久化的SQLAlchemy ORM事件钩子

2024-06-02 05:45:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我正致力于在SQLAlchemy事件中找到一种方法,在属性更新并持久化到数据库中时调用外部API。以下是我的背景:

An User model with an attribute named birthday. When an instance of User model gets updated and saved, I want to call to an external API to update this user's birthday accordingly.

我尝试过Attribute Events,但是,它会产生太多的点击,而且无法保证set/remove属性事件最终会被持久化(auto commit设置为False,当发生错误时事务将回滚)

Session Events也不起作用,因为它需要一个Session/SessionFactory作为参数,而且基于代码的位置太多,以至于已经使用了Session。在

我一直在查看官方文档中所有可能的SQLAlchemy ORM event hooks,但是我找不到任何一个满足我的要求。在

我想知道是否还有人了解如何在SQLAlchemy中实现这种组合事件触发器。谢谢。在


Tags: to方法anapi数据库model属性sqlalchemy
1条回答
网友
1楼 · 发布于 2024-06-02 05:45:51

可以通过组合多个事件来完成此操作。需要使用的特定事件取决于特定的应用程序,但基本思想是:

  1. [InstanceEvents.load]当一个实例被加载时,请记下这个事实:它是被加载的,并且以后不会被添加到会话中(我们只想在加载实例时保存初始状态)
  2. [AttributeEvents.set/append/remove]当一个属性发生变化时,记下它被改变的事实,如果必要的话,它是从什么地方改变的(如果不需要初始状态,前两个步骤是可选的)
  3. [SessionEvents.before_flush]刷新发生时,记下实际保存的实例
  4. [SessionEvents.before_commit]在提交完成之前,记下实例的当前状态(因为在提交之后,您可能无法再访问它)
  5. [SessionEvents.after_commit]提交完成后,启动自定义事件处理程序并清除保存的实例

一个有趣的挑战是事件的顺序。如果您执行session.commit()而不执行session.flush(),您会注意到before_commit事件在before_flush事件之前触发,这与在session.commit()之前执行session.flush()的场景不同。解决方案是在您的before_commit调用中调用session.flush()来强制排序。这可能不是百分之百的洁净,但在生产中对我很有效。在

以下是事件顺序的(简单)图表:

begin
load
(save initial state)
set attribute
...
flush
set attribute
...
flush
...
(save modified state)
commit
(fire off "object saved and changed" event)

完整示例

^{pr2}$

正如你所见,它有点复杂,也不太符合人体工程学。如果将它集成到ORM中会更好,但我也知道不这样做可能有原因。在

相关问题 更多 >