SQLAlchemy的特点是 Event Listening 整个核心和ORM使用的系统。在ORM中,有各种各样的事件侦听器钩子,这些钩子在API级别上记录在 ORM事件 . 这些年来,这些活动的集合不断增加,包括许多非常有用的新活动,以及一些与以前不太相关的旧活动。本节将尝试介绍主要事件挂钩以及它们可能被使用的时间。
可能最广泛使用的一系列事件是“持久性”事件,它对应于 flush process . 刷新是指对对象的挂起更改做出所有决定,然后以插入、更新和删除语句的形式发送到数据库。
before_flush()
¶这个 SessionEvents.before_flush()
钩子是到目前为止最常用的事件,当应用程序希望确保在刷新进行时对数据库进行额外的持久性更改时,可以使用钩子。使用 SessionEvents.before_flush()
以便对对象进行操作以验证其状态,并在持久化之前组合其他对象和引用。在这次活动中, 可以安全地操纵会话的状态 也就是说,可以附加新对象,删除对象,自由更改对象上的单个属性,这些更改将在事件挂钩完成时拉入刷新过程。
典型 SessionEvents.before_flush()
Hook将负责扫描集合 Session.new
, Session.dirty
和 Session.deleted
以寻找将要发生事情的对象。
用于说明 SessionEvents.before_flush()
,参见示例,例如 使用历史记录表进行版本控制 和 使用临时行进行版本控制 .
after_flush()
¶这个 SessionEvents.after_flush()
在为刷新进程发出SQL之后调用hook,但是 之前 刷新对象的状态已更改。也就是说,你仍然可以检查 Session.new
, Session.dirty
和 Session.deleted
集合以查看刚刚刷新的内容,还可以使用历史跟踪功能,如 AttributeState
以查看刚刚持续的更改。在 SessionEvents.after_flush()
事件,可以根据观察到的变化向数据库发出额外的SQL。
after_flush_postexec()
¶SessionEvents.after_flush_postexec()
很快就要调用了 SessionEvents.after_flush()
,但被调用 after 对象的状态已被修改,以解释刚刚发生的刷新。这个 Session.new
, Session.dirty
和 Session.deleted
这里的集合通常是完全空的。使用 SessionEvents.after_flush_postexec()
以检查已完成对象的标识映射,并可能发出其他SQL。在这个钩子中,有能力对对象进行新的更改,这意味着 Session
将再次进入“肮脏”状态;机械的 Session
这会使它刷新 再一次 如果在此钩子中检测到新的更改,则在 Session.commit()
否则,挂起的更改将作为下一个正常刷新的一部分捆绑在一起。当钩子检测到 Session.commit()
,计数器确保在100次迭代后停止这方面的无限循环,如果 SessionEvents.after_flush_postexec()
钩子不断地添加每次调用时要刷新的新状态。
除了齐平级别的钩子之外,还有一组更细粒度的钩子,因为它们是基于每个对象调用的,并且是基于插入、更新或删除而断开的。这些是映射器持久性挂钩,它们也非常流行,但是需要更谨慎地处理这些事件,因为它们在已经在进行的刷新过程的上下文中进行;许多操作在这里进行并不安全。
事件是:
每个事件都通过 Mapper
,映射对象本身,以及 Connection
它正用于发出INSERT、UPDATE或DELETE语句。这些事件的吸引力很明显,因为如果应用程序希望将某些活动与某个特定类型的对象通过插入持久化时相关联,那么钩子是非常特定的;与 SessionEvents.before_flush()
事件,不需要像 Session.new
为了找到目标。但是,表示要发出的每个insert、update、delete语句的完整列表的flush计划已经 已经决定了 当调用这些事件时,在此阶段不能进行任何更改。因此,对给定对象的唯一可能更改是基于属性 地方的 到对象的行。对对象或其他对象的任何其他更改都将影响 Session
将无法正常工作。
这些映射器级别的持久性事件不支持的操作包括:
映射集合追加、添加、删除、删除、放弃等。
映射关系属性set/del事件,即 someobject.related = someotherobject
原因 Connection
通过是鼓励 这里进行简单的SQL操作 ,直接在 Connection
例如递增计数器或在日志表中插入额外的行。当处理 Connection
,预计将使用核心级别的SQL操作;例如 SQL表达式语言教程 .
还有许多每个对象的操作根本不需要在刷新事件中处理。最常见的选择是简单地在对象内部建立附加状态 __init__()
方法,例如创建要与新对象关联的其他对象。如中所述使用验证器 简单验证器 是另一种方法;这些函数可以截获对属性的更改,并在目标对象上建立响应属性更改的附加状态更改。使用这两种方法,对象在到达刷新步骤之前处于正确的状态。
事件的另一个用例是跟踪对象的生命周期。这是指在 Quickie对象状态简介 .
1.1 新版功能: 添加了一个事件系统,该系统截获对象在 Session
.
以上所有状态都可以通过事件完全跟踪。每个事件都代表一个不同的状态转换,这意味着开始状态和目标状态都是被跟踪的部分。除初始瞬态事件外,所有事件都是 Session
对象或类,这意味着它们可以与特定的 Session
对象:
from sqlalchemy import event
from sqlalchemy.orm import Session
session = Session()
@event.listens_for(session, 'transient_to_pending')
def object_is_pending(session, obj):
print("new pending: %s" % obj)
或与 Session
类本身,以及 sessionmaker
,这可能是最有用的形式:
from sqlalchemy import event
from sqlalchemy.orm import sessionmaker
maker = sessionmaker()
@event.listens_for(maker, 'transient_to_pending')
def object_is_pending(session, obj):
print("new pending: %s" % obj)
当然,侦听器可以堆叠在一个函数之上,这很可能是常见的。例如,要跟踪所有进入持久状态的对象:
@event.listens_for(maker, "pending_to_persistent")
@event.listens_for(maker, "deleted_to_persistent")
@event.listens_for(maker, "detached_to_persistent")
@event.listens_for(maker, "loaded_as_persistent")
def detect_all_persistent(session, instance):
print("object is now persistent: %s" % instance)
第一次构造时的所有映射对象都以 transient . 在此状态下,对象单独存在,并且不与任何 Session
. 对于这个初始状态,没有特定的“转换”事件,因为没有 Session
但是,如果要在创建任何瞬态对象时拦截,则 InstanceEvents.init()
方法可能是最好的事件。此事件应用于特定的类或超类。例如,要截获特定声明性基的所有新对象:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event
Base = declarative_base()
@event.listens_for(Base, "init", propagate=True)
def intercept_init(instance, args, kwargs):
print("new transient: %s" % instance)
瞬变对象变成 pending 当它第一次与 Session
通过 Session.add()
或 Session.add_all()
方法。对象也可能成为 Session
由于 "cascade" 从显式添加的引用对象。使用 SessionEvents.transient_to_pending()
事件:
@event.listens_for(sessionmaker, "transient_to_pending")
def intercept_transient_to_pending(session, object_):
print("transient to pending: %s" % object_)
这个 pending 对象变为 persistent 当刷新进行并且实例发生insert语句时。对象现在有一个标识密钥。跟踪挂起到永久 SessionEvents.pending_to_persistent()
事件:
@event.listens_for(sessionmaker, "pending_to_persistent")
def intercept_pending_to_persistent(session, object_):
print("pending to persistent: %s" % object_)
这个 pending 对象可以还原为 transient 如果 Session.rollback()
方法在刷新挂起对象之前调用,或者如果 Session.expunge()
在刷新对象之前为其调用方法。跟踪待处理到瞬态 SessionEvents.pending_to_transient()
事件:
@event.listens_for(sessionmaker, "pending_to_transient")
def intercept_pending_to_transient(session, object_):
print("transient to pending: %s" % object_)
对象可以出现在 Session
直接在 persistent 从数据库加载时的状态。跟踪此状态转换与加载时跟踪对象同义,并且与使用 InstanceEvents.load()
实例级事件。然而, SessionEvents.loaded_as_persistent()
事件作为以会话为中心的钩子提供,用于拦截通过此特定路径进入持久状态的对象:
@event.listens_for(sessionmaker, "loaded_as_persistent")
def intercept_loaded_as_persistent(session, object_):
print("object loaded into persistent state: %s" % object_)
如果 Session.rollback()
方法是为一个事务调用的,在该事务中,首先将对象添加为挂起的。在回滚的情况下,使该对象持久化的insert语句将回滚,并从 Session
再次变成短暂的。使用 SessionEvents.persistent_to_transient()
事件钩子::
@event.listens_for(sessionmaker, "persistent_to_transient")
def intercept_persistent_to_transient(session, object_):
print("persistent to transient: %s" % object_)
持久对象进入 deleted 在刷新过程中从数据库中删除标记为删除的对象时的状态。注意这是 不一样 正如当 Session.delete()
为目标对象调用方法。这个 Session.delete()
仅方法 标志 要删除的对象;实际的DELETE语句在刷新进行之前不会发出。刷新之后,目标对象将出现“已删除”状态。
在“已删除”状态下,对象仅与 Session
. 它不存在于身份图中,也不存在于 Session.deleted
在挂起删除时引用的集合。
从“已删除”状态,对象可以在提交事务时转到分离状态,或者在回滚事务时回到持久状态。
使用跟踪持续到已删除的转换 SessionEvents.persistent_to_deleted()
::
@event.listens_for(sessionmaker, "persistent_to_deleted")
def intercept_persistent_to_deleted(session, object_):
print("object was DELETEd, is now in deleted state: %s" % object_)
删除的对象变为 detached 当会话的事务被提交时。后 Session.commit()
方法,数据库事务是最终的,并且 Session
现在完全丢弃已删除的对象并删除与之相关的所有关联。使用跟踪已删除到已分离的转换 SessionEvents.deleted_to_detached()
::
@event.listens_for(sessionmaker, "deleted_to_detached")
def intercept_deleted_to_detached(session, object_):
print("deleted to detached: %s" % object_)
注解
当对象处于已删除状态时, InstanceState.deleted
属性,可使用访问 inspect(object).deleted
,返回true。然而,当对象被分离时, InstanceState.deleted
将再次返回false。要检测对象是否已被删除,无论是否已分离,请使用 InstanceState.was_deleted
访问器。
持久对象变成 detached 当对象与 Session
,通过 Session.expunge()
, Session.expunge_all()
或 Session.close()
方法。
注解
一个对象也可能变成 隐式分离 如果拥有 Session
被应用程序取消引用并由于垃圾收集而丢弃。在这种情况下, 未发出任何事件 .
使用 SessionEvents.persistent_to_detached()
事件:
@event.listens_for(sessionmaker, "persistent_to_detached")
def intecept_persistent_to_detached(session, object_):
print("object became detached: %s" % object_)
当分离的对象与使用 Session.add()
或等效方法。使用 SessionEvents.detached_to_persistent()
事件:
@event.listens_for(sessionmaker, "detached_to_persistent")
def intecept_detached_to_persistent(session, object_):
print("object became persistent again: %s" % object_)
这个 deleted 对象可以还原为 persistent 状态何时使用 Session.rollback()
方法。使用 SessionEvents.deleted_to_persistent()
事件:
@event.listens_for(sessionmaker, "transient_to_pending")
def intercept_transient_to_pending(session, object_):
print("transient to pending: %s" % object_)
事务事件允许在事务边界出现时通知应用程序 Session
水平以及何时 Session
更改上的事务状态 Connection
对象。
SessionEvents.after_transaction_create()
, SessionEvents.after_transaction_end()
-这些事件跟踪 Session
以一种不特定于单个数据库连接的方式。这些事件旨在帮助集成事务跟踪系统,例如 zope.sqlalchemy
. 当应用程序需要将某些外部作用域与 Session
. 这些挂钩反映了 Session
因为它们跟踪逻辑的“子事务”以及“嵌套”(例如保存点)事务。
SessionEvents.before_commit()
, SessionEvents.after_commit()
, SessionEvents.after_begin()
, SessionEvents.after_rollback()
, SessionEvents.after_soft_rollback()
-这些事件允许从数据库连接的角度跟踪事务事件。 SessionEvents.after_begin()
尤其是每个连接事件;a Session
当这些连接在当前事务中使用时,维护多个连接的将单独为每个连接发出此事件。然后,当DBAPI连接本身直接接收到回滚或提交指令时,回滚和提交事件引用。
属性更改事件允许在修改对象上的特定属性时拦截。这些活动包括 AttributeEvents.set()
, AttributeEvents.append()
和 AttributeEvents.remove()
. 这些事件非常有用,特别是对于每个对象的验证操作;但是,使用“验证器”钩子(在后台使用这些钩子)通常更方便;请参见 简单验证器 关于这方面的背景。属性事件也是后向引用机制的背后。演示属性事件使用的示例在 属性检测 .