事件

优质
小牛编辑
129浏览
2023-12-01

SQLAlchemy包括一个事件API,它发布了各种钩子到SQLAlchemy核心和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_connectionconnection_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() 该参数应按名称传递给函数,而不是按位置传递。

0.9.0 新版功能: 增加可选 named 参数调度到事件调用。

目标

这个 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://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)

事件引用

sqlacalchemy core和sqlacalchemy orm都具有多种事件挂钩:

  • 核心事件 -这些在 核心事件 并且包括特定于连接池生命周期、SQL语句执行、事务生命周期以及模式创建和拆卸的事件挂钩。

  • ORM事件 -这些在 ORM事件 ,并包括特定于类和属性检测的事件挂钩、对象初始化挂钩、更改挂钩上的属性、会话状态、刷新和提交挂钩、映射器初始化、对象/结果填充和每个实例的持久挂钩。

API引用

Object NameDescription

contains(target, identifier, fn)

如果给定的目标/ident/fn设置为侦听,则返回true。

listen(target, identifier, fn, *args, **kw)

为给定目标注册侦听器函数。

listens_for(target, identifier, *args, **kw)

将函数修饰为给定目标+标识符的侦听器。

remove(target, identifier, fn)

删除事件侦听器。

function sqlalchemy.event.listen(target, identifier, fn, *args, **kw)

为给定目标注册侦听器函数。

这个 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维护者通常不使用或建议使用此功能,但提供此功能是为了确保某些用户定义的函数可以在其他函数之前运行,例如在以下情况下 Changing the sql_mode in MySQL

  • named (bool) -- 使用命名参数传递时,函数参数规范中列出的名称将用作字典中的键。看见 命名参数样式

  • once (bool) -- 内网/内部接口使用情况。已弃用。此参数将提供每个给定目标仅运行一次事件函数。但是,这并不意味着自动取消注册监听器函数;关联任意数量的监听器而不显式删除它们将导致内存无限增长,即使在以下情况下也是如此 once=True 是指定的。

  • propagate (bool) -- 这个 propagate 在处理ORM规范和映射事件时,可以使用kwarg。看见 MapperEventsMapperEvents.before_mapper_configured() 举个例子。

  • retval (bool) -- 此标志仅适用于特定的事件侦听器,每个侦听器都包括说明何时应该使用它的文档。默认情况下,任何侦听器都不需要返回值。但是,某些侦听器确实支持返回值的特殊行为,并在其文档中包含 retval=True 标志是要处理的返回值所必需的。事件侦听器套件,它们利用 listen.retval 包括 ConnectionEventsAttributeEvents

注解

这个 listen() 不能在运行目标事件的同时调用函数。这意味着线程安全,也意味着不能从监听器函数内部为自己添加事件。要运行的事件列表存在于可变集合中,该集合在迭代期间无法更改。

事件注册和删除不打算是一个“高速”操作;它是一个配置操作。对于需要快速与大规模事件关联和解除关联的系统,请使用从单个侦听器内部处理的可变结构。

参见

listens_for()

remove()

function sqlalchemy.event.listens_for(target, identifier, *args, **kw)

将函数修饰为给定目标+标识符的侦听器。

这个 listens_for() decorator是sqlAlchemy事件系统的主接口的一部分,记录在 事件 .

此函数通常与 listens()

例如。::

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, identifier, fn)

删除事件侦听器。

这里的参数应该与发送到 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 也被传播到 SomeMappedClassremove() 函数将恢复所有这些操作。

注解

这个 remove() 不能在运行目标事件的同时调用函数。这对线程安全有影响,也意味着事件不能从侦听器函数内部自行删除。要运行的事件列表存在于可变集合中,该集合在迭代期间无法更改。

事件注册和删除不打算是一个“高速”操作;它是一个配置操作。对于需要快速与大规模事件关联和解除关联的系统,请使用从单个侦听器内部处理的可变结构。

在 1.0.0 版更改: -A collections.deque() 对象现在用作事件列表的容器,该列表在迭代集合时显式禁止集合突变。

参见

listen()

function sqlalchemy.event.contains(target, identifier, fn)

如果给定的目标/ident/fn设置为侦听,则返回true。