SQLAlchemy 2.0 文档
- 上一页: Core API 基础知识
- 下一页: 运行时检查 API
- 向上: 首页
- 本页内容
事件¶
SQLAlchemy 包括一个事件 API,它发布了广泛的钩子,用于 SQLAlchemy Core 和 ORM 的内部。
事件注册¶
订阅事件通过一个单一的 API 入口点发生,即 listen()
函数,或者可替代地使用 listens_for()
装饰器。这些函数接受一个目标,一个标识要拦截的事件的字符串标识符,以及一个用户定义的监听函数。这些函数的其他位置和关键字参数可能被特定类型的事件支持,这些事件可能为给定的事件函数指定备用接口,或者根据给定的目标提供关于辅助事件目标的指令。
事件的名称和相应的监听器函数的参数签名是从一个类绑定的规范方法派生出来的,该方法存在于绑定到文档中描述的标记类。例如,PoolEvents.connect()
的文档表明事件名称是 "connect"
,并且用户定义的监听器函数应该接收两个位置参数
from sqlalchemy.event import listen
from sqlalchemy.pool import Pool
def my_on_connect(dbapi_con, connection_record):
print("New DBAPI connection:", dbapi_con)
listen(Pool, "connect", my_on_connect)
使用 listens_for()
装饰器进行监听看起来像
from sqlalchemy.event import listens_for
from sqlalchemy.pool import Pool
@listens_for(Pool, "connect")
def my_on_connect(dbapi_con, connection_record):
print("New DBAPI connection:", dbapi_con)
命名参数风格¶
监听器函数可以接受一些参数风格的变体。以 PoolEvents.connect()
为例,此函数被记录为接收 dbapi_connection
和 connection_record
参数。我们可以选择通过名称接收这些参数,通过建立一个接受 **keyword
参数的监听器函数,通过传递 named=True
给 listen()
或 listens_for()
from sqlalchemy.event import listens_for
from sqlalchemy.pool import Pool
@listens_for(Pool, "connect", named=True)
def my_on_connect(**kw):
print("New DBAPI connection:", kw["dbapi_connection"])
当使用命名参数传递时,函数参数规范中列出的名称将用作字典中的键。
命名风格通过名称传递所有参数,而不管函数签名如何,因此可以列出特定的参数,以任何顺序排列,只要名称匹配即可
from sqlalchemy.event import listens_for
from sqlalchemy.pool import Pool
@listens_for(Pool, "connect", named=True)
def my_on_connect(dbapi_connection, **kw):
print("New DBAPI connection:", dbapi_connection)
print("Connection record:", kw["connection_record"])
上面,**kw
的存在告诉 listens_for()
参数应该通过名称而不是位置传递给函数。
目标¶
listen()
函数在目标方面非常灵活。它通常接受类、这些类的实例以及可以从中派生适当目标的相关类或对象。例如,上面提到的 "connect"
事件接受 Engine
类和对象以及 Pool
类和对象
from sqlalchemy.event import listen
from sqlalchemy.pool import Pool, QueuePool
from sqlalchemy import create_engine
from sqlalchemy.engine import Engine
import psycopg2
def connect():
return psycopg2.connect(user="ed", host="127.0.0.1", dbname="test")
my_pool = QueuePool(connect)
my_engine = create_engine("postgresql+psycopg2://ed@localhost/test")
# associate listener with all instances of Pool
listen(Pool, "connect", my_on_connect)
# associate listener with all instances of Pool
# via the Engine class
listen(Engine, "connect", my_on_connect)
# associate listener with my_pool
listen(my_pool, "connect", my_on_connect)
# associate listener with my_engine.pool
listen(my_engine, "connect", my_on_connect)
修饰符¶
一些监听器允许将修饰符传递给 listen()
。这些修饰符有时为监听器提供备用调用签名。例如,对于 ORM 事件,一些事件监听器可以具有返回值,该返回值修改后续处理。默认情况下,没有监听器需要返回值,但是通过传递 retval=True
,可以支持此值
def validate_phone(target, value, oldvalue, initiator):
"""Strip non-numeric characters from a phone number"""
return re.sub(r"\D", "", value)
# setup listener on UserContact.phone attribute, instructing
# it to use the return value
listen(UserContact.phone, "set", validate_phone, retval=True)
事件和多进程¶
SQLAlchemy 的事件钩子使用 Python 函数和对象实现,因此事件通过 Python 函数调用传播。Python 多进程遵循我们考虑操作系统多进程的相同方式,例如父进程派生子进程,因此我们可以使用相同的模型来描述 SQLAlchemy 事件系统的行为。
在父进程中注册的事件钩子将存在于从该父进程派生的新子进程中,在注册钩子之后,因为子进程在生成时以父进程中所有现有 Python 结构的副本开始。在注册钩子之前已经存在的子进程将不会接收这些新的事件钩子,因为对父进程中的 Python 结构所做的更改不会传播到子进程。
对于事件本身,这些是 Python 函数调用,它们没有任何在进程之间传播的能力。SQLAlchemy 的事件系统不实现任何进程间通信。可以实现事件钩子,这些钩子在其中使用 Python 进程间消息传递,但这需要由用户实现。
事件参考¶
SQLAlchemy Core 和 SQLAlchemy ORM 都具有各种各样的事件钩子
API 参考¶
对象名称 | 描述 |
---|---|
contains(target, identifier, fn) |
如果给定的 target/ident/fn 设置为监听,则返回 True。 |
listen(target, identifier, fn, *args, **kw) |
为给定的目标注册一个监听器函数。 |
listens_for(target, identifier, *args, **kw) |
将函数装饰为给定目标 + 标识符的监听器。 |
remove(target, identifier, fn) |
移除一个事件监听器。 |
- function sqlalchemy.event.listen(target: Any, identifier: str, fn: Callable[[...], Any], *args: Any, **kw: Any) → None¶
为给定的目标注册一个监听器函数。
listen()
函数是 SQLAlchemy 事件系统的主要接口的一部分,记录在 事件 中。例如:
from sqlalchemy import event from sqlalchemy.schema import UniqueConstraint def unique_constraint_name(const, table): const.name = "uq_%s_%s" % (table.name, list(const.columns)[0].name) event.listen( UniqueConstraint, "after_parent_attach", unique_constraint_name )
- 参数:
insert¶ (bool) – 事件处理程序的默认行为是在发现时将装饰的用户定义函数附加到已注册事件监听器的内部列表中。如果用户使用
insert=True
注册函数,SQLAlchemy 将在发现时将该函数插入(前置)到内部列表中。此功能通常不被 SQLAlchemy 维护者使用或推荐,但提供它是为了确保某些用户定义的函数可以在其他函数之前运行,例如当 在 MySQL 中更改 sql_mode 时。once¶ (bool) – 私有/内部 API 用法。已弃用。此参数将提供事件函数对于给定的目标仅运行一次。然而,它并不意味着自动注销监听器函数;即使指定了
once=True
,关联任意数量的监听器而不显式删除它们也会导致内存无限增长。propagate¶ (bool) – 当使用 ORM 检测和映射事件时,
propagate
关键字参数可用。有关示例,请参阅MapperEvents
和MapperEvents.before_mapper_configured()
。retval¶ (bool) –
此标志仅适用于特定的事件监听器,每个监听器都包含解释何时应使用它的文档。默认情况下,没有监听器需要返回值。但是,某些监听器确实支持返回值的特殊行为,并在其文档中包含
retval=True
标志对于返回值被处理是必要的。使用
listen.retval
的事件监听器套件包括ConnectionEvents
和AttributeEvents
。
注意
listen()
函数不能在目标事件正在运行时同时调用。这对线程安全有影响,也意味着不能从其自身的监听器函数内部添加事件。要运行的事件列表存在于迭代期间无法更改的可变集合中。事件注册和移除不旨在成为“高速”操作;它是一种配置操作。对于需要快速关联和取消关联事件以实现高规模的系统,请使用从单个监听器内部处理的可变结构。
- function sqlalchemy.event.listens_for(target: Any, identifier: str, *args: Any, **kw: Any) → Callable[[Callable[[...], Any]], Callable[[...], Any]]¶
将函数装饰为给定目标 + 标识符的监听器。
listens_for()
装饰器是 SQLAlchemy 事件系统的主要接口的一部分,记录在 事件 中。此函数通常与
listen()
共享相同的关键字参数。例如:
from sqlalchemy import event from sqlalchemy.schema import UniqueConstraint @event.listens_for(UniqueConstraint, "after_parent_attach") def unique_constraint_name(const, table): const.name = "uq_%s_%s" % (table.name, list(const.columns)[0].name)
给定函数也可以仅为事件的第一次调用调用,使用
once
参数@event.listens_for(Mapper, "before_configure", once=True) def on_config(): do_config()
警告
once
参数并不意味着在首次调用监听器函数后自动注销它;监听器条目将保持与目标对象关联。即使指定了once=True
,关联任意数量的监听器而不显式删除它们也会导致内存无限增长。另请参阅
listen()
- 事件监听的一般描述
- function sqlalchemy.event.remove(target: Any, identifier: str, fn: Callable[[...], Any]) → None¶
移除一个事件监听器。
此处的参数应与发送到
listen()
的参数完全匹配;所有由此调用产生的事件注册都将通过使用相同的参数调用remove()
来撤消。例如:
# if a function was registered like this... @event.listens_for(SomeMappedClass, "before_insert", propagate=True) def my_listener_function(*arg): pass # ... it's removed like this event.remove(SomeMappedClass, "before_insert", my_listener_function)
上面,与
SomeMappedClass
关联的监听器函数也传播到SomeMappedClass
的子类;remove()
函数将撤消所有这些操作。注意
remove()
函数不能在目标事件正在运行时同时调用。这对线程安全有影响,也意味着不能从其自身的监听器函数内部移除事件。要运行的事件列表存在于迭代期间无法更改的可变集合中。事件注册和移除不旨在成为“高速”操作;它是一种配置操作。对于需要快速关联和取消关联事件以实现高规模的系统,请使用从单个监听器内部处理的可变结构。
另请参阅
- function sqlalchemy.event.contains(target: Any, identifier: str, fn: Callable[[...], Any]) → bool¶
如果给定的 target/ident/fn 设置为监听,则返回 True。
flambé! 龙和 炼金术士 图像设计由 Rotem Yaari 创作并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档最后生成于:2025 年 3 月 11 日星期二下午 02:40:17 EDT