SqlAlchemy-2-0-中文文档-十二-

SqlAlchemy 2.0 中文文档(十二)

原文:docs.sqlalchemy.org/en/20/contents.html

上下文/线程本地会话

原文:docs.sqlalchemy.org/en/20/orm/contextual.html

回顾一下何时构建会话,何时提交,何时关闭?一节中,介绍了“会话范围”的概念,强调了在 Web 应用程序中链接Session的范围与 Web 请求的范围之间的实践。大多数现代 Web 框架都包括集成工具,以便自动管理Session的范围,并且应该使用这些工具,只要它们可用。

SQLAlchemy 包括其自己的辅助对象,它有助于建立用户定义的Session范围。它也被第三方集成系统用于帮助构建它们的集成方案。

该对象是scoped_session对象,它表示一组Session对象的注册表。如果您对注册表模式不熟悉,可以在企业架构模式中找到一个很好的介绍。

警告

scoped_session注册表默认使用 Python 的threading.local()来跟踪Session实例。这不一定与所有应用服务器兼容,特别是那些使用绿色线程或其他替代形式的并发控制的服务器,这可能导致在中高并发情况下使用时出现竞争条件(例如,随机发生的故障)。请阅读下面的线程局部范围和在 Web 应用程序中使用线程局部范围以更充分地理解使用threading.local()来跟踪Session对象的影响,并在使用不基于传统线程的应用服务器时考虑更明确的范围。

注意

scoped_session对象是许多 SQLAlchemy 应用程序中非常流行和有用的对象。然而,重要的是要注意,它只提供了解决Session管理问题的一个方法。如果你对 SQLAlchemy 还不熟悉,特别是如果“线程本地变量”这个术语对你来说很陌生,我们建议你如果可能的话,首先熟悉一下诸如Flask-SQLAlchemyzope.sqlalchemy之类的现成集成系统。

通过调用它并传递一个可以创建新Session对象的工厂来构造scoped_session。工厂只是在调用时生成一个新对象的东西,在Session的情况下,最常见的工厂是在本节前面介绍的sessionmaker。下面我们举例说明这种用法:

>>> from sqlalchemy.orm import scoped_session
>>> from sqlalchemy.orm import sessionmaker

>>> session_factory = sessionmaker(bind=some_engine)
>>> Session = scoped_session(session_factory)

我们创建的scoped_session对象现在将在我们“调用”注册表时调用sessionmaker

>>> some_session = Session()

在上面,some_sessionSession的一个实例,我们现在可以用它来与数据库交互。这个相同的Session也存在于我们创建的scoped_session注册表中。如果我们第二次调用注册表,我们会得到相同的Session

>>> some_other_session = Session()
>>> some_session is some_other_session
True

这种模式允许应用程序的不同部分调用全局的scoped_session,这样所有这些区域就可以在不需要显式传递的情况下共享同一个会话。我们在注册表中建立的Session将保持不变,直到我们显式告诉注册表将其销毁,方法是调用scoped_session.remove()

>>> Session.remove()

scoped_session.remove() 方法首先调用当前 Session 上的 Session.close(),其效果是首先释放任何由 Session 拥有的连接/事务资源,然后丢弃 Session 本身。这里的“释放”意味着连接被返回到其连接池,并且任何事务状态都被回滚,最终使用底层 DBAPI 连接的 rollback() 方法。

此时,scoped_session 对象是“空的”,在再次调用时将创建一个新的 Session。如下所示,这不是我们之前所拥有的相同 Session

>>> new_session = Session()
>>> new_session is some_session
False

上述一系列步骤简要说明了“注册表”模式的概念。有了这个基本概念,我们可以讨论这种模式如何进行的一些细节。

隐式方法访问

scoped_session 的工作很简单;为所有请求它的人保留一个 Session。为了更透明地访问这个 Sessionscoped_session 还包括代理行为,这意味着注册表本身可以直接像 Session 一样对待;当在此对象上调用方法时,它们会代理到注册表维护的底层 Session

Session = scoped_session(some_factory)

# equivalent to:
#
# session = Session()
# print(session.scalars(select(MyClass)).all())
#
print(Session.scalars(select(MyClass)).all())

上述代码实现了通过调用注册表获取当前 Session 然后使用该 Session 的相同任务。

线程本地作用域

熟悉多线程编程的用户会注意到,将任何东西表示为全局变量通常是一个坏主意,因为这意味着全局对象将被许多线程同时访问。Session 对象完全设计成以非并发方式使用,从多线程的角度来看,这意味着“一次只能在一个线程中”。因此,我们上面对 scoped_session 的使用示例,其中相同的 Session 对象在多次调用中保持不变,暗示着需要某种处理方式,以使多个线程中的多次调用实际上不会获取到同一个会话的句柄。我们称这个概念为线程本地存储,意思是,使用一个特殊的对象,它将为每个应用程序线程维护一个独立的对象。Python 通过 threading.local() 构造提供了这个功能。scoped_session 对象默认使用此对象作为存储,以便为所有调用 scoped_session 注册表的人维护一个单一的 Session,但仅在单个线程范围内。在不同线程中调用注册表的调用者会获取一个仅限于该其他线程的 Session 实例。

使用这种技术,scoped_session 提供了一种快速且相对简单(如果熟悉线程本地存储的话)的方式,在应用程序中提供一个单一的全局对象,可以安全地从多个线程调用。

scoped_session.remove() 方法始终会删除与该线程关联的当前 Session(如果有的话)。然而,threading.local() 对象的一个优点是,如果应用程序线程本身结束,那么该线程的“存储”也会被垃圾回收。因此,在一个产生并销毁线程的应用程序中使用线程局部范围实际上是“安全”的,而不需要调用 scoped_session.remove()。然而,事务本身的范围,即通过 Session.commit()Session.rollback() 结束它们,通常仍然是必须在适当的时候明确安排的东西,除非应用程序实际上将线程的寿命与事务的寿命绑定在一起。## 使用线程局部范围与 Web 应用程序

如在何时构建会话,何时提交它,何时关闭它?一节中所讨论的,一个 web 应用程序是围绕着网络请求的概念构建的,并且将这样的应用程序与 Session 集成通常意味着将 Session 与该请求相关联。事实证明,大多数 Python web 框架,特别是异步框架 Twisted 和 Tornado 之类的著名例外,以简单的方式使用线程,使得一个特定的网络请求在一个单独的工作线程的范围内接收、处理和完成。当请求结束时,工作线程被释放到一个工作线程池中,在那里它可以处理另一个请求。

这种简单的网络请求和线程的对应关系意味着,将 Session 关联到一个线程意味着它也与在该线程内运行的网络请求关联,反之亦然,前提是 Session 只在网络请求开始后创建并在网络请求结束前被销毁。因此,将 scoped_session 用作将 Session 与 web 应用程序集成的快速方法是一种常见做法。下面的顺序图说明了这个流程:

Web Server          Web Framework        SQLAlchemy ORM Code
--------------      --------------       ------------------------------
startup        ->   Web framework        # Session registry is established
                    initializes          Session = scoped_session(sessionmaker())

incoming
web request    ->   web request     ->   # The registry is *optionally*
                    starts               # called upon explicitly to create
                                         # a Session local to the thread and/or request
                                         Session()

                                         # the Session registry can otherwise
                                         # be used at any time, creating the
                                         # request-local Session() if not present,
                                         # or returning the existing one
                                         Session.execute(select(MyClass)) # ...

                                         Session.add(some_object) # ...

                                         # if data was modified, commit the
                                         # transaction
                                         Session.commit()

                    web request ends  -> # the registry is instructed to
                                         # remove the Session
                                         Session.remove()

                    sends output      <-
outgoing web    <-
response

使用上述流程,将 Session 与 Web 应用程序集成的过程只有两个要求:

  1. 在 Web 应用程序首次启动时创建一个单一的 scoped_session 注册表,确保此对象可被应用程序的其余部分访问。

  2. 确保在 Web 请求结束时调用 scoped_session.remove(),通常是通过与 Web 框架的事件系统集成来建立“请求结束时”事件。

如前所述,上述模式只是整合 Session 到 Web 框架的一种潜在方式,特别是假定Web 框架将 Web 请求与应用线程关联。然而,强烈建议使用 Web 框架本身提供的集成工具,如果有的话,而不是 scoped_session

特别是,虽然使用线程本地存储很方便,但最好将 Session 直接与请求关联,而不是与当前线程关联。下一节关于自定义范围详细介绍了一种更高级的配置,可以将 scoped_session 的使用与直接基于请求的范围,或任何类型的范围结合起来。

使用自定义创建的范围

scoped_session 对象的默认行为“线程本地”范围只是如何“范围” Session 的许多选项之一。可以根据任何现有的“我们正在处理的当前事物”的系统来定义自定义范围。

假设 Web 框架定义了一个库函数 get_current_request()。使用此框架构建的应用程序可以随时调用此函数,结果将是表示正在处理的当前请求的某种 Request 对象。如果 Request 对象是可哈希的,那么此函数可以很容易地与 scoped_session 集成,以将 Session 与请求关联起来。下面我们结合 Web 框架提供的假设事件标记器 on_request_end,说明了这一点,该标记器允许在请求结束时调用代码:

from my_web_framework import get_current_request, on_request_end
from sqlalchemy.orm import scoped_session, sessionmaker

Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)

@on_request_end
def remove_session(req):
    Session.remove()

在上述情况中,我们以通常的方式实例化scoped_session,唯一的区别是我们将请求返回函数作为“scopefunc”传递。这指示scoped_session在每次调用注册表返回当前Session时使用此函数生成字典键。在这种情况下,我们特别需要确保实现可靠的“删除”系统,因为否则此字典不会自行管理。

上下文会话 API

对象名称 描述
QueryPropertyDescriptor 描述应用于类级别scoped_session.query_property()属性的类型。
scoped_session 提供Session对象的作用域管理。
ScopedRegistry 可以根据“作用域”函数存储单个类的一个或多个实例的注册表。
ThreadLocalRegistry 使用threading.local()变量进行存储的ScopedRegistry
class sqlalchemy.orm.scoped_session

提供Session对象的作用域管理。

参见上下文/线程本地会话教程。

注意

在使用异步 I/O (asyncio)时,应该使用与scoped_session类异步兼容的async_scoped_session类。

成员

call(), init(), add(), add_all(), autoflush, begin(), begin_nested(), bind, bulk_insert_mappings(), bulk_save_objects(), bulk_update_mappings(), close(), close_all(), commit(), configure(), connection(), delete(), deleted, dirty, execute(), expire(), expire_all(), expunge(), expunge_all(), flush(), get(), get_bind(), get_one(), identity_key(), identity_map, info, is_active, is_modified(), merge(), new, no_autoflush, object_session(), query(), query_property(), refresh(), remove(), reset(), rollback(), scalar(), scalars(), session_factory

类签名

sqlalchemy.orm.scoped_session (typing.Generic)

method __call__(**kw: Any) → _S

返回当前Session,如果不存在,则使用scoped_session.session_factory创建它。

参数:

**kw – 关键字参数将传递给scoped_session.session_factory可调用对象,如果不存在现有的Session。如果存在Session并且已传递关键字参数,则会引发InvalidRequestError

method __init__(session_factory: sessionmaker[_S], scopefunc: Callable[[], Any] | None = None)

构建一个新的scoped_session

参数:

  • session_factory – 一个用于创建新的Session实例的工厂。通常情况下,但不一定,这是一个sessionmaker的实例。

  • scopefunc – 可选函数,定义当前范围。如果未传递,scoped_session对象假定“线程本地”范围,并将使用 Python 的threading.local()来维护当前Session。如果传递了函数,该函数应返回一个可散列的令牌;此令牌将用作字典中的键,以便存储和检索当前Session

method add(instance: object, _warn: bool = True) → None

将一个对象放入此Session

代表scoped_session类的Session类的代理。

当通过Session.add()方法传递的对象处于瞬态状态时,它们将移动到挂起状态,直到下一次刷新,然后它们将移动到持久状态。

当通过Session.add()方法传递的对象处于分离状态时,它们将直接移动到持久状态。

如果Session使用的事务被回滚,则在它们被传递给Session.add()时处于瞬态的对象将被移回瞬态状态,并且将不再存在于此Session中。

另请参阅

Session.add_all()

添加新项目或现有项目 - 在使用会话基础知识中

method add_all(instances: Iterable[object]) → None

将给定的实例集添加到此Session中。

代表scoped_session类的Session类的代理。

有关Session.add()的一般行为描述,请参阅文档。

另请参阅

Session.add()

添加新项目或现有项目 - 在使用会话基础知识中

attribute autoflush

代表scoped_session类的Session.autoflush属性的代理。

method begin(nested: bool = False) → SessionTransaction

如果尚未开始事务,则在此Session上开始事务或嵌套事务。

代表scoped_session类的Session类的代理。

Session对象具有自动开始行为,因此通常不需要显式调用Session.begin()方法。但是,它可以用于控制事务状态开始的范围。

当用于开始最外层事务时,如果此Session已在事务内部,则会引发错误。

参数:

嵌套 - 如果为 True,则开始 SAVEPOINT 事务,并等效于调用Session.begin_nested()。有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction对象。请注意,SessionTransaction充当 Python 上下文管理器,允许在“with”块中使用Session.begin()。请参阅显式开始获取示例。

另请参阅

自动开始

管理事务

Session.begin_nested()

method begin_nested() → SessionTransaction

在此 Session 上开始一个“嵌套”事务,例如 SAVEPOINT。

代理 scoped_session 类的 Session 类。

目标数据库及其关联的驱动程序必须支持 SQL SAVEPOINT,该方法才能正确运行。

有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction 对象。请注意,SessionTransaction 作为上下文管理器,允许在“with”块中使用 Session.begin_nested()。有关用法示例,请参阅使用 SAVEPOINT。

另请参阅

使用 SAVEPOINT

Serializable isolation / Savepoints / Transactional DDL - 为了使 SAVEPOINT 正确工作,SQLite 驱动程序需要特殊的解决方法。对于 asyncio 用例,请参阅 Serializable isolation / Savepoints / Transactional DDL(asyncio 版本) 部分。

attribute bind

代理 scoped_session 类的 Session.bind 属性。

method bulk_insert_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]], return_defaults: bool = False, render_nulls: bool = False) → None

对给定的映射字典列表执行批量插入。

代理 scoped_session 类的 Session 类。

传统功能

此方法是 SQLAlchemy 2.0 系列的传统功能。对于现代批量插入和更新,请参阅 ORM 批量 INSERT 语句 和 ORM 根据主键批量更新。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:

  • mapper - 一个映射类,或者实际的 Mapper 对象,表示映射列表中表示的单个对象类型。

  • mappings – 一个字典序列,每个字典包含要插入的映射行的状态,以映射类上的属性名称表示。如果映射引用多个表,例如联合继承映射,每个字典必须包含要填充到所有表中的所有键。

  • return_defaults

    当设置为 True 时,将更改 INSERT 过程以确保获取新生成的主键值。通常设置此参数的原因是启用联合表继承映射的批量插入。

    注意

    对于不支持 RETURNING 的后端,Session.bulk_insert_mappings.return_defaults 参数可以显著降低性能,因为无法批量处理 INSERT 语句。请参阅 “插入多个值”行为的 INSERT 语句 了解哪些后端会受到影响的背景信息。

  • render_nulls

    当设置为 True 时,None 的值将导致 NULL 值包含在 INSERT 语句中,而不是将列从 INSERT 中省略。这允许要 INSERT 的所有行具有相同的列集,从而允许将所有行批量发送到 DBAPI。通常,包含与上一行不同的 NULL 值组合的每个列集必须省略 INSERT 语句中的一系列不同列,这意味着必须将其作为单独的语句发出。通过传递此标志,可以确保将所有行的完整集合批量处理到一个批次中;但是,成本是将被省略的列调用的服务器端默认值将被跳过,因此必须确保这些值不是必需的。

    警告

    当设置此标志时,不会为那些以 NULL 插入的列调用服务器端默认 SQL 值;NULL 值将被明确发送。必须小心确保整个操作不需要调用服务器端默认函数。

请参阅

ORM 启用的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_save_objects()

Session.bulk_update_mappings()

method bulk_save_objects(objects: Iterable[object], return_defaults: bool = False, update_changed_only: bool = True, preserve_order: bool = True) → None

对给定对象列表执行批量保存。

代理Session类,代表scoped_session类。

旧特性

此方法作为 SQLAlchemy 2.0 系列的传统功能。有关现代批量 INSERT 和 UPDATE,请参见 ORM 批量 INSERT 语句和 ORM 批量按主键 UPDATE 部分。

对于一般的 ORM 映射对象的 INSERT 和 UPDATE,请优先使用标准的工作单元数据管理模式,在 SQLAlchemy 统一教程的 ORM 数据操作中引入。SQLAlchemy 2.0 现在使用现代方言的“Insert Many Values”行为用于 INSERT 语句,解决了以前批量 INSERT 速度慢的问题。

参数:

  • objects

    一个映射对象实例的序列。映射对象按原样持久化,并且在之后Session相关联。

    对于每个对象,该对象是作为 INSERT 还是 UPDATE 发送取决于传统操作中Session使用的相同规则;如果对象具有InstanceState.key属性设置,则假定对象为“分离”,并将导致 UPDATE。否则,使用 INSERT。

    在 UPDATE 的情况下,语句根据已更改的属性分组,因此将成为每个 SET 子句的主题。如果update_changed_only为 False,则将应用每个对象中存在的所有属性到 UPDATE 语句中,这可能有助于将语句分组到更大的 executemany()中,并且还将减少检查属性历史记录的开销。

  • return_defaults – 当为 True 时,将缺少生成默认值的值的行插入“一次”,以便主键值可用。特别是,这将允许联合继承和其他多表映射正确插入,而无需提前提供主键值;但是,Session.bulk_save_objects.return_defaults 大大降低了该方法的性能收益。强烈建议请使用标准的Session.add_all()方法。

  • update_changed_only – 当为 True 时,基于每个状态中已记录更改的属性渲染 UPDATE 语句。当为 False 时,除主键属性外,将所有存在的属性渲染到 SET 子句中。

  • preserve_order - 当为 True 时,插入和更新的顺序与给定对象的顺序完全匹配。当为 False 时,常见类型的对象被分组为插入和更新,以便提供更多的批处理机会。

另请参阅

ORM-Enabled INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_update_mappings()

method bulk_update_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]) → None

对给定的映射字典列表执行批量更新。

代理了scoped_session类的Session类。

传统功能

作为 SQLAlchemy 2.0 系列的一个传统功能。有关现代批量 INSERT 和 UPDATE,请参阅 ORM 批量 INSERT 语句和 ORM 通过主键进行批量 UPDATE 部分。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:

  • mapper - 一个映射类,或者表示映射列表中所表示的单一对象的实际Mapper对象。

  • mappings - 一系列字典,每个字典包含要更新的映射行的状态,以映射类上的属性名称为准。如果映射涉及多个表,比如联接继承映射,则每个字典可能包含对所有表对应的键。所有这些已存在且不是主键的键都将应用于 UPDATE 语句的 SET 子句;所需的主键值将应用于 WHERE 子句。

另请参阅

ORM-Enabled INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_save_objects()

method close() → None

关闭此Session所使用的事务资源和 ORM 对象。

代理了scoped_session类的Session类。

这会清除与此Session关联的所有 ORM 对象,结束任何正在进行的事务,并释放此Session自身从关联的Engine对象中签出的任何Connection对象。然后,该操作将使Session处于可以再次使用的状态。

提示

在默认运行模式下,Session.close()方法不会阻止再次使用会话Session本身实际上没有明确的“关闭”状态;它只是表示Session将释放所有数据库连接和 ORM 对象。

将参数Session.close_resets_only设置为False将使close最终,意味着会禁止对会话的任何进一步操作。

从版本 1.4 开始更改:Session.close()方法不会立即创建新的SessionTransaction对象;只有在再次为数据库操作使用Session时才会创建新的SessionTransaction

另请参见

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.reset() - 一个类似的方法,行为类似于close(),参数Session.close_resets_only设置为True

classmethod close_all() → None

关闭所有内存中的会话。

代理scoped_session类的Session类。

自 1.3 版本起已弃用:Session.close_all() 方法已弃用,将在将来的版本中删除。请参考close_all_sessions()

method commit() → None

刷新待处理更改并提交当前事务。

代理了scoped_session类的Session类。

当 COMMIT 操作完成时,所有对象都被完全过期,擦除其内部内容,在下次访问对象时会自动重新加载。在此期间,这些对象处于过期状态,如果从Session中分离,它们将无法运行。此外,在使用基于 asyncio 的 API 时不支持此重新加载操作。Session.expire_on_commit参数可用于禁用此行为。

Session没有正在进行的事务时,表示自上次调用Session.commit()以来没有对此Session进行任何操作,则该方法将开始并提交一个仅限内部的“逻辑”事务,通常不会影响数据库,除非检测到待处理的刷新更改,但仍将调用事件处理程序和对象过期规则。

最外层数据库事务会无条件提交,自动释放任何正在进行的 SAVEPOINT。

请参阅。

提交。

管理事务。

在使用 AsyncSession 时避免隐式 IO。

method configure(**kwargs: Any) → None

重新配置由此scoped_session使用的sessionmaker

查看sessionmaker.configure()

method connection(bind_arguments: _BindArguments | None = None, execution_options: CoreExecuteOptionsParameter | None = None) → Connection

返回一个对应于此Session对象的事务状态的Connection对象。

代理了scoped_session类的Session类。

返回当前事务对应的Connection,如果没有进行中的事务,则开始一个新事务并返回Connection(注意,直到发出第一个 SQL 语句之前,才会与 DBAPI 建立事务状态)。

多绑定或未绑定的Session对象中的歧义可以通过任何可选的关键字参数来解决。最终,这使得使用get_bind()方法来解析。

参数:

  • bind_arguments – 绑定参数字典。可能包括“mapper”、“bind”、“clause”、“其他传递给Session.get_bind()的自定义参数。

  • execution_options

    将传递给Connection.execution_options()的执行选项字典,仅在首次获取连接时。如果连接已经存在于Session中,则会发出警告并忽略参数。

    另请参阅

    设置事务隔离级别 / DBAPI AUTOCOMMIT

method delete(instance: object) → None

将实例标记为已删除。

代表scoped_session类为Session类代理。

当传递的对象被假定为持久的或分离的时,调用该方法后,对象将保持在持久状态,直到下一次刷新进行。在此期间,该对象还将成为Session.deleted集合的成员。

下一次刷新进行时,对象将转移到删除状态,表示在当前事务中为其行发出了DELETE语句。当事务成功提交时,已删除的对象将转移到分离状态,并且不再存在于此Session中。

另请参阅

删除 - 在使用会话的基础知识

attribute deleted

所有在此Session中标记为“已删除”的实例集合

代表scoped_session类为Session类进行了代理。

attribute dirty

被视为脏的所有持久实例的集合。

代表scoped_session类为Session类进行了代理。

例如:

some_mapped_object in session.dirty

实例在被修改但未被删除时被视为脏。

请注意,这个“脏”计算是“乐观”的;大多数属性设置或集合修改操作都会将实例标记为“脏”,并将其放入这个集合中,即使属性的值没有净变化。在刷新时,将每个属性的值与其先前保存的值进行比较,如果没有净变化,则不会发生 SQL 操作(这是一项更昂贵的操作,因此只在刷新时执行)。

要检查实例是否对其属性有可操作的净变化,请使用Session.is_modified()方法。

method execute(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, _parent_execute_state: Any | None = None, _add_event: Any | None = None) → Result[Any]

执行 SQL 表达式构造。

代表scoped_session类为Session类进行了代理。

返回表示语句执行结果的Result对象。

例如:

from sqlalchemy import select
result = session.execute(
    select(User).where(User.id == 5)
)

Session.execute()的 API 合同类似于Connection.execute(),2.0 风格版本的Connection

从版本 1.4 开始变更:当使用 2.0 风格 ORM 使用时,Session.execute()方法现在是 ORM 语句执行的主要点。

参数:

  • statement – 可执行的语句(即Executable表达式,如select())。

  • params – 可选字典或字典列表,其中包含绑定的参数值。如果是单个字典,则执行单行操作;如果是字典列表,则将调用“executemany”。每个字典中的键必须对应于语句中存在的参数名称。

  • execution_options

    可选的执行选项字典,将与语句执行相关联。此字典可以提供Connection.execution_options()接受的选项子集,并且还可以提供只在 ORM 上下文中理解的其他选项。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments – 用于确定绑定的其他参数的字典。可能包括“mapper”,“bind”或其他自定义参数。此字典的内容传递给Session.get_bind()方法。

返回:

一个Result对象。

method expire(instance: object, attribute_names: Iterable[str] | None = None) → None

将实例的属性过期。

代表scoped_session类的Session类的代理。

将实例的属性标记为过时。下次访问过期属性时,将向Session对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与先前在同一事务中读取的相同值,而不管该事务之外的数据库状态的变化。

要同时使Session中的所有对象过期,请使用Session.expire_all()

Session对象的默认行为是在调用Session.rollback()Session.commit()方法时将所有状态过期,以便为新的事务加载新状态。因此,仅在当前事务中发出了非 ORM SQL 语句的特定情况下调用Session.expire()才有意义。

参数:

  • instance – 要刷新的实例。

  • attribute_names – 可选的字符串属性名称列表,指示要过期的属性子集。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expire_all() → None

使此会话中的所有持久实例过期。

代表 scoped_session 类,为 Session 类提供代理。

当下次访问持久实例的任何属性时,将使用 Session 对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与之前在该事务中读取的相同值,而不考虑该事务之外的数据库状态的更改。

要使单个对象和这些对象上的单个属性过期,请使用 Session.expire()

Session 对象的默认行为是在调用 Session.rollback()Session.commit() 方法时使所有状态过期,以便为新事务加载新状态。因此,通常不需要调用 Session.expire_all(),假设事务是隔离的。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expunge(instance: object) → None

从此 Session 中移除实例。

代表 scoped_session 类,为 Session 类提供代理。

这将释放对实例的所有内部引用。将根据 expunge 级联规则应用级联。

method expunge_all() → None

从此 Session 中移除所有对象实例。

代表 scoped_session 类,为 Session 类提供代理。

这相当于在此 Session 中对所有对象调用 expunge(obj)

method flush(objects: Sequence[Any] | None = None) → None

将所有对象更改刷新到数据库。

代表Session类的scoped_session类。

将所有待处理的对象创建、删除和修改写入数据库,作为 INSERTs、DELETEs、UPDATEs 等。操作会自动按照会话的工作单元依赖解析器进行排序。

数据库操作将在当前事务上下文中发出,并且不会影响事务的状态,除非发生错误,在这种情况下,整个事务都将回滚。您可以在事务中随意刷新()以将更改从 Python 移动到数据库的事务缓冲区。

参数:

objects

可选;限制刷新操作仅对给定集合中存在的元素进行操作。

此功能适用于极为狭窄的一组使用案例,其中可能需要在完全刷新()发生之前对特定对象进行操作。不适用于常规用途。

method get(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O | None

返回基于给定主键标识符的实例,如果找不到则返回None

代表Session类的scoped_session类。

例如:

my_user = session.get(User, 5)

some_object = session.get(VersionedFoo, (5, 10))

some_object = session.get(
    VersionedFoo,
    {"id": 5, "version_id": 10}
)

从版本 1.4 开始:添加了Session.get(),它已从现在的遗留Query.get()方法中移动。

Session.get()是特殊的,它直接提供对Session的标识映射的访问。如果给定的主键标识符存在于本地标识映射中,则直接从此集合返回对象,并且不会发出 SQL,除非对象已被标记为完全过期。如果不存在,则执行 SELECT 以定位对象。

Session.get()还将执行检查,看对象是否存在于标识映射中并标记为过期 - 还会发出 SELECT 以刷新对象以及确保行仍然存在。如果不是,则引发ObjectDeletedError

参数:

  • entity – 指示要加载的实体类型的映射类或Mapper

  • ident

    代表主键的标量、元组或字典。对于复合(例如,多列)主键,应传递元组或字典。

    对于单列主键,标量调用形式通常是最方便的。如果一行的主键是值“5”,调用看起来像:

    my_object = session.get(SomeClass, 5)
    

    元组形式包含主键值,通常按照其对应于映射的Table对象的主键列的顺序排列,或者如果使用了Mapper.primary_key配置参数,则按照该参数使用的顺序排列。例如,如果一行的主键由整数数字“5, 10”表示,调用将如下所示:

    my_object = session.get(SomeClass, (5, 10))
    

    字典形式应包含键,对应于每个主键元素的映射属性名称。如果映射类具有存储对象主键值的属性 idversion_id,则调用将如下所示:

    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
    
  • options – 可选的加载器选项序列,如果发出查询,则将应用于该查询。

  • populate_existing – 导致该方法无条件发出 SQL 查询并使用新加载的数据刷新对象,无论对象是否已存在。

  • with_for_update – 可选布尔值 True,表示应该使用 FOR UPDATE,或者可以是一个包含标志的字典,表示用于 SELECT 的一组更具体的 FOR UPDATE 标志;标志应该与Query.with_for_update()方法的参数匹配。取代 Session.refresh.lockmode 参数。

  • execution_options

    可选的执行选项字典,如果发出查询,则与查询执行相关联。此字典可以提供Connection.execution_options()接受的选项子集,并且还可以提供只在 ORM 上下文中理解的其他选项。

    从版本 1.4.29 开始新增。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments

    用于确定绑定的附加参数字典。可能包括“mapper”、“bind”或其他自定义参数。此字典的内容传递给 Session.get_bind()方法。

返回:

对象实例,或 None

method get_bind(mapper: _EntityBindKey[_O] | None = None, *, clause: ClauseElement | None = None, bind: _SessionBind | None = None, _sa_skip_events: bool | None = None, _sa_skip_for_implicit_returning: bool = False, **kw: Any) → Engine | Connection

返回此Session绑定的“bind”。

代理为Session类,代表scoped_session类。

“bind”通常是 Engine 的实例,除非 Session 已经被明确地直接绑定到 Connection 的情况除外。

对于多重绑定或未绑定的 Session,使用 mapperclause 参数来确定要返回的适当绑定。

注意,当通过 ORM 操作调用 Session.get_bind(),比如 Session.query(),以及 Session.flush() 中的每个单独的 INSERT/UPDATE/DELETE 操作时,“mapper”参数通常会出现在调用中。

解析顺序为:

  1. 如果给定了 mapper 并且 Session.binds 存在,则根据首先使用的 mapper,然后使用的 mapped class,然后使用 mapped class 的 __mro__ 中存在的任何基类来定位绑定,从更具体的超类到更一般的超类。

  2. 如果给定了 clause 并且存在 Session.binds,则根据 Session.binds 中存在的给定 clause 中的 Table 对象来定位绑定。

  3. 如果存在 Session.binds,则返回该绑定。

  4. 如果给定了 clause,则尝试返回与 clause 最终关联的元数据的绑定。

  5. 如果给定了 mapper,则尝试返回与 mapper 映射到的 Table 或其他可选择的元数据最终关联的绑定。

  6. 如果找不到绑定,则会引发 UnboundExecutionError

注意,Session.get_bind() 方法可以在 Session 的用户定义的子类上被覆盖,以提供任何类型的绑定解析方案。请参阅自定义垂直分区中的示例。

参数:

  • mapper – 可选的映射类或相应的Mapper实例。绑定可以首先通过查看与此Session相关联的“绑定”映射来派生自Mapper,其次是通过查看与Mapper映射到的Table相关联的MetaData来派生绑定。

  • clause – 一个ClauseElement(即select()text()等)。如果未提供mapper参数或无法生成绑定,则将搜索给定的表达式构造以获取绑定元素,通常是与绑定的MetaData相关联的Table

另请参阅

分区策略(例如每个会话的多个数据库后端)

Session.binds

Session.bind_mapper()

Session.bind_table()

method get_one(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O

基于给定的主键标识符返回一个实例,如果找不到则引发异常。

代表scoped_session类的Session类的代理。

如果查询未选择任何行,则引发sqlalchemy.orm.exc.NoResultFound异常。

查看有关参数的详细文档,请参阅方法Session.get()

2.0.22 版中的新功能。

返回:

对象实例。

另请参阅

Session.get() - 相应的方法,用于

如果找不到提供的主键的行,则返回None

classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

返回一个标识键。

代表scoped_session类的Session类的代理。

这是identity_key()的别名。

attribute identity_map

代表scoped_session类的Session.identity_map属性的代理。

attribute info

用户可修改的字典。

代表scoped_session类的Session类的代理。

此字典的初始值可以使用Session构造函数或sessionmaker构造函数或工厂方法中的info参数进行填充。此处的字典始终局限于此Session并且可以独立于所有其他Session对象进行修改。

attribute is_active

如果此Session不处于“部分回滚”状态,则返回 True。

代表scoped_session类的Session类的代理。

从版本 1.4 开始更改:Session不再立即开始新事务,因此在首次实例化Session时,此属性将为 False。

“部分回滚”状态通常表示Session的刷新过程失败,并且必须发出Session.rollback()方法以完全回滚事务。

如果此Session根本不处于事务中,则在首次使用时Session将自动开始,因此在这种情况下Session.is_active将返回 True。

否则,如果此Session在事务中,并且该事务尚未在内部回滚,则Session.is_active也将返回 True。

另请参阅

“由于刷新期间先前的异常,此会话的事务已回滚。”(或类似)

Session.in_transaction()

method is_modified(instance: object, include_collections: bool = True) → bool

如果给定实例具有本地修改的属性,则返回True

代理scoped_session类为Session类。

此方法检索实例上每个受检的属性的历史记录,并将当前值与其先前提交的值进行比较(如果有)。

这实际上是对在Session.dirty集合中检查给定实例的更昂贵且准确的版本;会执行每个属性净“脏”状态的完整测试。

例如:

return session.is_modified(someobject)

此方法有一些注意事项适用:

  • Session.dirty集合中存在的实例在使用此方法进行测试时可能报告False。这是因为对象可能已经通过属性变异接收到更改事件,从而将其放置在Session.dirty中,但最终状态与从数据库加载的状态相同,在此处没有净变化。

  • 当应用新值时,如果标量属性未加载或已过期,则可能未记录先前设置的值 - 在这些情况下,即使最终对其数据库值没有净变化,也假定属性已更改。大多数情况下,SQLAlchemy 在设置事件发生时不需要“旧”值,因此如果旧值不存在,则会跳过 SQL 调用的开销,这基于以下假设:标量值通常需要更新,在那些几种情况中不需要,平均而言比发出防御性 SELECT 要便宜。

    只有在属性容器的active_history标志设置为True时,才会无条件地在设置时获取“旧”值。通常为主键属性和不是简单多对一的标量对象引用设置此标志。要为任意映射列设置此标志,请使用带有column_property()active_history参数。

参数:

  • instance – 要测试的映射实例的待处理更改。

  • include_collections – 表示是否应该包含多值集合在操作中。将其设置为False是一种仅检测基于本地列的属性(即标量列或多对一外键)的方法,这些属性在刷新时会导致此实例的更新。

method merge(instance: _O, *, load: bool = True, options: Sequence[ORMOption] | None = None) → _O

将给定实例的状态复制到此Session中的相应实例。

代理为scoped_session类代表Session类。

Session.merge() 检查源实例的主键属性,并尝试将其与会话中具有相同主键的实例进行协调。如果在本地找不到,它将尝试根据主键从数据库加载对象,如果找不到,则创建一个新实例。然后将源实例上的每个属性的状态复制到目标实例。然后方法返回生成的目标实例;如果原始源实例尚未关联,则保持不变且未关联Session

此操作如果关联映射使用cascade="merge",将级联到关联的实例。

有关合并的详细讨论,请参阅合并。

参数:

  • instance – 要合并的实例。

  • load

    布尔值,当为 False 时,merge() 切换到“高性能”模式,导致它放弃发出历史事件以及所有数据库访问。此标志用于诸如从二级缓存传输对象图到Session,或将刚加载的对象传输到工作线程或进程拥有的Session中而无需重新查询数据库的情况。

    load=False 的用例添加了一个警告,即给定对象必须处于“干净”状态,即没有要刷新的挂起更改 - 即使传入对象与任何Session都分离。这样,当合并操作填充本地属性并级联到相关对象和集合时,值可以“盖章”到目标对象上,而不会生成任何历史或属性事件,并且不需要将传入数据与可能未加载的任何现有相关对象或集合进行协调。load=False 的结果对象始终以“干净”方式生成,因此只有给定对象也应该“干净”,否则这表明方法的误用。

  • options

    可选的加载器选项序列,将在合并操作从数据库加载现有对象的版本时应用于Session.get()方法。

    1.4.24 版本中新增。

另请参阅

make_transient_to_detached() - 提供了将单个对象“合并”到Session中的替代方法

attribute new

在此Session中标记为“新”的所有实例的集合。

代表scoped_session类的Session类的代理。

attribute no_autoflush

返回一个禁用自动刷新的上下文管理器。

代表scoped_session类的Session类的代理。

例如:

with session.no_autoflush:

    some_object = SomeClass()
    session.add(some_object)
    # won't autoflush
    some_object.related_thing = session.query(SomeRelated).first()

with:块内进行的操作不会受到查询访问时发生的刷新的影响。这在初始化涉及现有数据库查询的一系列对象时非常有用,其中未完成的对象不应立即被刷新。

classmethod object_session(instance: object) → Session | None

返回一个对象所属的Session

代表scoped_session类的Session类的代理。

这是object_session()的别名。

method query(*entities: _ColumnsClauseArgument[Any], **kwargs: Any) → Query[Any]

返回与此Session对应的新Query对象。

代表scoped_session类的Session类的代理。

注意Query对象在 SQLAlchemy 2.0 中已被废弃;现在使用select()构造 ORM 查询。

另请参阅

SQLAlchemy 统一教程

ORM 查询指南

旧版查询 API - 旧版 API 文档

method query_property(query_cls: Type[Query[_T]] | None = None) → QueryPropertyDescriptor

返回一个类属性,当调用时会针对该类和当前Session产生一个旧版的Query对象。

旧版特性

scoped_session.query_property() 访问器专门针对传统的 Query 对象,不被视为 2.0-style ORM 使用的一部分。

例如:

from sqlalchemy.orm import QueryPropertyDescriptor
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker

Session = scoped_session(sessionmaker())

class MyClass:
    query: QueryPropertyDescriptor = Session.query_property()

# after mappers are defined
result = MyClass.query.filter(MyClass.name=='foo').all()

默认情况下,通过会话配置的查询类产生会话的实例。要覆盖并使用自定义实现,请提供一个 query_cls 可调用对象。将使用类的映射器作为位置参数和会话关键字参数调用可调用对象。

在类上放置的查询属性的数量没有限制。

method refresh(instance: object, attribute_names: Iterable[str] | None = None, with_for_update: ForUpdateParameter = None) → None

对给定实例的过期和刷新属性。

代理为 scoped_session 类代表 Session 类。

选定的属性将首先过期,就像使用 Session.expire() 时一样;然后将向数据库发出 SELECT 语句,以使用当前事务中可用的当前值刷新面向列的属性。

如果对象已经急加载了,那么 relationship() 导向的属性也将立即加载,并使用它们最初加载的急加载策略。

新版本 1.4 中:- Session.refresh() 方法现在也可以刷新急加载的属性。

如果惰性加载的关系不在 Session.refresh.attribute_names 中命名,则它们将保持为“惰性加载”属性,并且不会隐式刷新。

2.0.4 版本中的更改:Session.refresh() 方法现在将刷新那些在 Session.refresh.attribute_names 集合中显式命名的惰性加载的 relationship() 导向的属性。

提示

虽然 Session.refresh() 方法能够刷新列和关系导向属性,但其主要焦点是在单个实例上刷新本地列导向属性。对于更开放式的“刷新”功能,包括在具有显式控制关系加载器策略的同时刷新多个对象的属性的能力,请改用 populate existing 功能。

注意,高度隔离的事务将返回在同一事务中先前读取的相同值,而不管该事务外部数据库状态的变化如何。刷新属性通常只在事务开始时有意义,此时数据库行尚未被访问。

参数:

  • attribute_names – 可选。一个字符串属性名称的可迭代集合,指示要刷新的属性的子集。

  • with_for_update – 可选布尔值 True,表示应该使用 FOR UPDATE,或者可以是一个包含标志的字典,指示要在 SELECT 中使用一组更具体的 FOR UPDATE 标志;标志应该与 Query.with_for_update() 的参数匹配。覆盖 Session.refresh.lockmode 参数。

另请参阅

Refreshing / Expiring - 入门材料

Session.expire()

Session.expire_all()

Populate Existing - 允许任何 ORM 查询按照正常加载的方式刷新对象。

method remove() → None

如果存在,释放当前 Session

这首先会在当前 Session 上调用 Session.close() 方法,释放仍在持有的任何现有的事务/连接资源;具体地,会回滚事务。然后丢弃 Session。在同一作用域内的下一次使用时,scoped_session 将生成一个新的 Session 对象。

method reset() → None

结束此 Session 使用的事务资源和 ORM 对象,将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会将会...

代理Session类,代表scoped_session类。

此方法提供了与Session.close()方法历史上提供的相同的“仅重置”行为,其中Session的状态被重置,就像对象是全新的,准备好再次使用一样。然后,此方法可能对将Session.close_resets_only设置为FalseSession对象有用,以便“仅重置”行为仍然可用。

新版本 2.0.22 中的内容。

另请参阅

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.close() - 当参数Session.close_resets_only设置为False时,类似的方法还会阻止对会话的重新使用。

method rollback() → None

回滚当前进行中的事务。

代理Session类,代表scoped_session类。

如果没有事务正在进行,则此方法将被忽略。

该方法总是回滚最顶层的数据库事务,丢弃可能正在进行的任何嵌套事务。

另请参阅

回滚

管理事务

method scalar(statement: Executable, params: _CoreSingleExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → Any

执行语句并返回标量结果。

代理Session类,代表scoped_session类。

使用方法和参数与Session.execute()相同;返回结果是一个标量 Python 值。

method scalars(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → ScalarResult[Any]

执行语句并将结果作为标量返回。

代理Session类,代表scoped_session类。

使用和参数与 Session.execute() 相同;返回结果是一个过滤对象 ScalarResult,该对象将返回单个元素而不是 Row 对象。

返回:

一个 ScalarResult 对象

新特性在版本 1.4.24 中添加:增加了 Session.scalars()

新特性在版本 1.4.26 中添加:增加了scoped_session.scalars()

另见

选择 ORM 实体 - 将Session.execute()的行为与Session.scalars()进行对比

attribute session_factory: sessionmaker[_S]

提供给 __init__ 的 session_factory 存储在这个属性中,以后可以访问。当需要一个新的非范围 Session 时,这可能会很有用。

class sqlalchemy.util.ScopedRegistry

一个可以基于“作用域”函数存储一个或多个单个类实例的注册表。

该对象实现了 __call__ 作为“getter”,因此通过调用 myregistry() 返回当前范围的包含对象。

参数:

  • createfunc – 一个可调用的函数,返回要放置在注册表中的新对象

  • scopefunc – 一个可调用的函数,它将返回一个用于存储/检索对象的键。

成员

init(), clear(), has(), set()

类签名

sqlalchemy.util.ScopedRegistry (typing.Generic)

method __init__(createfunc: Callable[[], _T], scopefunc: Callable[[], Any])

构建一个新的 ScopedRegistry

参数:

  • createfunc – 一个创建函数,如果当前范围中不存在,则会生成一个新值。

  • scopefunc – 返回表示当前范围的可哈希令牌的函数(例如,当前线程标识符)。

method clear() → None

清除当前范围,如果有的话。

method has() → bool

如果对象存在于当前范围中,则返回 True。

method set(obj: _T) → None

设置当前范围的值。

class sqlalchemy.util.ThreadLocalRegistry

使用 threading.local() 变量进行存储的 ScopedRegistry

类签名

sqlalchemy.util.ThreadLocalRegistrysqlalchemy.util.ScopedRegistry

class sqlalchemy.orm.QueryPropertyDescriptor

描述应用于类级别的scoped_session.query_property()属性的类型。

新版本 2.0.5 中新增。

类签名

sqlalchemy.orm.QueryPropertyDescriptortyping_extensions.Protocol

隐式方法访问

scoped_session的工作很简单;为所有请求它的人保存一个Session。为了更透明地访问这个Sessionscoped_session还包括代理行为,意味着可以直接将注册表本身视为Session;当在这个对象上调用方法时,它们会被代理到注册表维护的基础Session上:

Session = scoped_session(some_factory)

# equivalent to:
#
# session = Session()
# print(session.scalars(select(MyClass)).all())
#
print(Session.scalars(select(MyClass)).all())

上述代码完成了与通过调用注册表获取当前Session相同的任务,然后使用该Session

线程本地作用域

对于熟悉多线程编程的用户来说,将任何东西表示为全局变量通常都是一个坏主意,因为这意味着全局对象将被许多线程同时访问。Session对象完全设计成以非并发方式使用,从多线程的角度来看,这意味着“一次只能在一个线程中”。因此,我们上面的scoped_session使用示例,其中同一个Session对象在多个调用之间保持不变,表明需要有一些进程存在,以确保许多线程中的多个调用实际上不会获得相同的会话句柄。我们将此概念称为线程本地存储,这意味着使用一个特殊对象,该对象将维护每个应用程序线程的独立对象。Python 通过threading.local()构造提供了这一功能。scoped_session对象默认使用此对象作为存储,以便在调用scoped_session注册表的所有调用者中维护单个Session,但仅在单个线程的范围内。在不同线程中调用注册表的调用者将获得一个针对该其他线程本地的Session实例。

使用这种技术,scoped_session提供了一种快速而相对简单(如果熟悉线程本地存储的话)的方式,在应用程序中提供一个可以安全地从多个线程调用的单一全局对象。

与往常一样,scoped_session.remove()方法会删除当前与线程关联的Session(如果有的话)。然而,threading.local()对象的一个优点是,如果应用程序线程本身结束,那么该线程的“存储”也会被垃圾回收。因此,在应用程序生成和销毁线程的情况下,使用线程本地作用域实际上是“安全”的,而无需调用scoped_session.remove()。然而,事务本身的范围,即通过Session.commit()Session.rollback()结束它们,通常仍然是必须在适当时候显式安排的,除非应用程序实际上将线程的寿命与事务的寿命绑定在一起。

在 Web 应用程序中使用线程本地作用域

如在何时构建会话、何时提交以及何时关闭会话?一节中所讨论的,Web 应用程序的架构围绕着web 请求的概念展开,而将这样的应用程序与Session集成通常意味着Session将与该请求相关联。事实证明,大多数 Python Web 框架(Twisted 和 Tornado 等异步框架是显著的例外)都以简单的方式使用线程,这样一个特定的 web 请求就在一个工作线程的范围内接收、处理和完成。当请求结束时,工作线程被释放到一个工作线程池中,在那里它可以处理另一个请求。

Web 请求与线程的这种简单对应关系意味着将Session与线程关联也意味着它也与在该线程中运行的 web 请求相关联,反之亦然,前提是Session仅在 Web 请求开始后创建,并在 Web 请求结束前销毁。因此,将scoped_session作为将Session与 Web 应用程序集成的一种快速方法是一种常见做法。下面的时序图说明了这个流程:

Web Server          Web Framework        SQLAlchemy ORM Code
--------------      --------------       ------------------------------
startup        ->   Web framework        # Session registry is established
                    initializes          Session = scoped_session(sessionmaker())

incoming
web request    ->   web request     ->   # The registry is *optionally*
                    starts               # called upon explicitly to create
                                         # a Session local to the thread and/or request
                                         Session()

                                         # the Session registry can otherwise
                                         # be used at any time, creating the
                                         # request-local Session() if not present,
                                         # or returning the existing one
                                         Session.execute(select(MyClass)) # ...

                                         Session.add(some_object) # ...

                                         # if data was modified, commit the
                                         # transaction
                                         Session.commit()

                    web request ends  -> # the registry is instructed to
                                         # remove the Session
                                         Session.remove()

                    sends output      <-
outgoing web    <-
response

使用上述流程,将 Session 与 Web 应用程序集成的过程具有确切的两个要求:

  1. 当 Web 应用程序首次启动时创建单个 scoped_session 注册表,确保此对象可被应用程序的其余部分访问。

  2. 确保在 Web 请求结束时调用 scoped_session.remove(),通常通过与 Web 框架的事件系统集成以建立“请求结束时”事件来实现。

如前所述,上述模式仅是将 Session 与 Web 框架集成的一种潜在方式,特别是假设Web 框架将 Web 请求与应用程序线程关联。但是,强烈建议如果有的话,使用 Web 框架本身提供的集成工具,而不是 scoped_session

特别地,虽然使用线程本地可能很方便,但最好将 Session 与请求直接关联,而不是与当前线程关联。下一节关于自定义作用域详细介绍了一种更高级的配置,可以将 scoped_session 的使用与直接基于请求的作用域或任何类型的作用域相结合。

使用自定义创建的作用域

scoped_session 对象的“线程本地”作用域是“对 Session 进行作用域”多种选项之一。可以基于任何现有的获取“我们正在处理的当前事物”的系统定义自定义作用域。

假设一个 Web 框架定义了一个名为 get_current_request() 的库函数。使用该框架构建的应用程序可以随时调用此函数,其结果将是表示正在处理的当前请求的某种 Request 对象。如果 Request 对象是可散列的,那么此函数可以很容易地与 scoped_session 集成以将 Session 与请求关联起来。下面我们结合 Web 框架提供的假设事件标记 on_request_end 来说明这一点,该事件标记允许在请求结束时调用代码:

from my_web_framework import get_current_request, on_request_end
from sqlalchemy.orm import scoped_session, sessionmaker

Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)

@on_request_end
def remove_session(req):
    Session.remove()

在上面的例子中,我们以通常的方式实例化 scoped_session,唯一不同的是我们将我们的请求返回函数作为“scopefunc”传递。这指示 scoped_session 使用此函数生成字典键,每当注册表被调用以返回当前 Session 时。在这种情况下,确保实现可靠的“移除”系统非常重要,因为否则这个字典不会自我管理。

上下文会话 API

对象名称 描述
QueryPropertyDescriptor 描述应用于类级 scoped_session.query_property() 属性的类型。
scoped_session 提供对 Session 对象的作用域管理。
ScopedRegistry 可以根据“范围”函数存储单个类的一个或多个实例的注册表。
ThreadLocalRegistry 使用 threading.local() 变量进行存储的 ScopedRegistry
class sqlalchemy.orm.scoped_session

提供对 Session 对象的作用域管理。

请查看上下文/线程本地会话以获取教程。

注意

当使用异步 I/O (asyncio)时,应该使用与 scoped_session 替代的异步兼容 async_scoped_session 类。

成员

call(), init(), add(), add_all(), autoflush, begin(), begin_nested(), bind, bulk_insert_mappings(), bulk_save_objects(), bulk_update_mappings(), close(), close_all(), commit(), configure(), connection(), delete(), deleted, dirty, execute(), expire(), expire_all(), expunge(), expunge_all(), flush(), get(), get_bind(), get_one(), identity_key(), identity_map, info, is_active, is_modified(), merge(), new, no_autoflush, object_session(), query(), query_property(), refresh(), remove(), reset(), rollback(), scalar(), scalars(), session_factory

类签名

sqlalchemy.orm.scoped_session (typing.Generic)

method __call__(**kw: Any) → _S

如果不存在,使用scoped_session.session_factory创建当前Session

参数:

**kw – 如果不存在现有的 Session,则将关键字参数传递给 scoped_session.session_factory 可调用对象。如果存在 Session 并且传递了关键字参数,则会引发 InvalidRequestError

method __init__(session_factory: sessionmaker[_S], scopefunc: Callable[[], Any] | None = None)

构建一个新的 scoped_session

参数:

  • session_factory – 用于创建新的 Session 实例的工厂。通常情况下,但并非一定如此,它是 sessionmaker 的实例。

  • scopefunc – 定义当前范围的可选函数。如果未传递,则 scoped_session 对象假定“线程本地”范围,并将使用 Python 的 threading.local() 来维护当前 Session。如果传递,则该函数应返回可哈希的标记;此标记将用作字典中的键,以便存储和检索当前 Session

method add(instance: object, _warn: bool = True) → None

将对象放入此 Session 中。

代表 scoped_session 类的 Session 类的代理。

当传递给 Session.add() 方法时处于 transient 状态的对象将移至 pending 状态,直到下一次刷新,此时它们将移至 persistent 状态。

当传递给 Session.add() 方法时处于 detached 状态的对象将直接移至 persistent 状态。

如果由 Session 使用的事务被回滚,则在传递给 Session.add() 时处于暂时状态的对象将被移回到 transient 状态,并且将不再存在于此 Session 中。

另请参见

Session.add_all()

添加新项目或现有项目 - 在使用会话基础知识中

method add_all(instances: Iterable[object]) → None

将给定的实例集合添加到此Session

代理Session类,代表scoped_session类。

有关一般行为描述,请参阅Session.add()的文档。

另请参阅

Session.add()

添加新项目或现有项目 - 在使用会话基础知识中

attribute autoflush

代表scoped_session类的Session.autoflush属性的代理。

method begin(nested: bool = False) → SessionTransaction

在此Session上开始事务或嵌套事务,如果尚未开始。

代理Session类,代表scoped_session类。

Session对象具有自动开始行为,因此通常不需要显式调用Session.begin()方法。但是,可以使用它来控制事务状态开始的范围。

用于开始最外层事务时,如果此Session已在事务内部,则会引发错误。

参数:

nested – 如果为 True,则开始一个 SAVEPOINT 事务,并等同于调用Session.begin_nested()。有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction对象。请注意,SessionTransaction充当 Python 上下文管理器,允许在“with”块中使用Session.begin()。有关示例,请参阅显式开始。

另请参阅

自动开始

管理事务

Session.begin_nested()

method begin_nested() → SessionTransaction

在此 Session 上开始一个“嵌套”事务,例如 SAVEPOINT。

代理scoped_session类的Session类。

目标数据库及其关联的驱动程序必须支持 SQL SAVEPOINT 才能使该方法正常运行。

有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction对象。请注意,SessionTransaction充当上下文管理器,允许在“with”块中使用Session.begin_nested()。请参阅使用 SAVEPOINT 以获取用法示例。

另请参阅

使用 SAVEPOINT

可序列化隔离/保存点/事务 DDL - 在 SQLite 驱动程序中,需要特殊的解决方法才能使 SAVEPOINT 正常工作。对于 asyncio 用例,请参阅可序列化隔离/保存点/事务 DDL(asyncio 版本)部分。

attribute bind

代理scoped_session类的Session.bind属性。

method bulk_insert_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]], return_defaults: bool = False, render_nulls: bool = False) → None

对给定的映射字典列表执行批量插入。

代理scoped_session类的Session类。

旧特性

此方法是 SQLAlchemy 2.0 系列的旧特性。对于现代批量 INSERT 和 UPDATE,请参阅 ORM 批量 INSERT 语句和 ORM 按主键批量 UPDATE 部分。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:

  • mapper – 一个映射类,或者实际的Mapper对象,代表映射列表中表示的对象类型。

  • mappings – 一系列字典,每个字典包含要插入的映射行的状态,以映射类上的属性名称表示。如果映射涉及多个表,例如联接继承映射,则每个字典必须包含要填充到所有表中的所有键。

  • return_defaults

    当为 True 时,插入过程将被改变,以确保新生成的主键值将被获取。通常,此参数的理由是为了使联接表继承映射能够被批量插入。

    注意

    对于不支持 RETURNING 的后端,Session.bulk_insert_mappings.return_defaults 参数可能会显著降低性能,因为 INSERT 语句无法再批量处理。请参阅“插入多个值”行为的 INSERT 语句以了解受影响的后端的背景信息。

  • render_nulls

    当为 True 时,None 的值将导致 NULL 值被包含在 INSERT 语句中,而不是从 INSERT 中省略该列。这允许所有要插入的行具有相同的列集,从而允许将完整的行集批量到 DBAPI。通常,每个包含与上一行不同组合的 NULL 值的列集必须从呈现的 INSERT 语句中省略一个不同的系列列,这意味着它必须作为一个单独的语句发出。通过传递此标志,保证了整个行集将被批处理到一个批次中;但代价是,由省略列调用的服务器端默认值将被跳过,因此必须小心确保这些值不是必需的。

    警告

    当设置此标志时,不会调用服务器端默认的 SQL 值用于那些以 NULL 插入的列;NULL 值将显式发送。必须小心确保整个操作不需要调用任何服务器端默认函数。

另请参阅

ORM-启用的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_save_objects()

Session.bulk_update_mappings()

method bulk_save_objects(objects: Iterable[object], return_defaults: bool = False, update_changed_only: bool = True, preserve_order: bool = True) → None

对给定对象列表执行批量保存。

代理 Session 类,代表 scoped_session 类。

遗留特性

该方法是 SQLAlchemy 2.0 系列的传统功能。对于现代批量插入和更新,请参阅 ORM 批量插入语句和 ORM 按主键批量更新部分。

对于一般的 ORM 映射对象的 INSERT 和 UPDATE,请优先使用标准的 unit of work 数据管理模式,介绍在 SQLAlchemy 统一教程的 ORM 数据操作部分。SQLAlchemy 2.0 现在使用现代方言的“插入多个值”的行为用于 INSERT 语句,解决了以前的批量插入缓慢的问题。

参数:

  • objects

    一系列映射对象实例。映射对象按原样保留,并且之后Session关联。

    对于每个对象,对象是作为 INSERT 还是 UPDATE 发送取决于Session在传统操作中使用的相同规则;如果对象具有InstanceState.key属性设置,则假定对象是“分离的”,将导致 UPDATE。否则,将使用 INSERT。

    在 UPDATE 的情况下,语句根据已更改的属性分组,并且因此将成为每个 SET 子句的主题。如果 update_changed_only 设置为 False,则每个对象中存在的所有属性都将应用于 UPDATE 语句,这可能有助于将语句组合成更大的 executemany(),还将减少检查属性历史的开销。

  • return_defaults – 当设置为 True 时,缺少生成默认值的值的行,即整数主键默认值和序列,将逐个插入,以便主键值可用。特别是这将允许加入继承和其他多表映射正确插入,无需提前提供主键值;然而,Session.bulk_save_objects.return_defaults 极大地降低了该方法的整体性能。强烈建议请使用标准的Session.add_all()方法。

  • update_changed_only – 当设置为 True 时,UPDATE 语句基于每个状态中已记录更改的属性。当设置为 False 时,所有存在的属性(主键属性除外)都将进入 SET 子句。

  • preserve_order – 当为 True 时,插入和更新的顺序与对象给出的顺序完全匹配。当为 False 时,常见类型的对象被分组为插入和更新,以便更多批处理机会。

另请参阅

启用 ORM 的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_update_mappings()

method bulk_update_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]) → None

执行给定映射字典列表的批量更新。

代表 scoped_session 类的 Session 类的代理。

遗留特性

此方法是 SQLAlchemy 2.0 系列的遗留特性。对于现代批量插入和更新,请参阅 ORM 批量插入语句 和 ORM 通过主键批量更新 部分。2.0 API 共享此方法的实现细节,并添加了新功能。

参数:

  • mapper – 一个映射类,或者实际的 Mapper 对象,代表映射列表中表示的单个对象类型。

  • mappings – 一个字典序列,每个字典包含要更新的映射行的状态,以映射类上的属性名称表示。如果映射涉及多个表,例如连接继承映射,则每个字典可能包含对应于所有表的键。所有那些出现且不是主键的键都应用于 UPDATE 语句的 SET 子句;必需的主键值应用于 WHERE 子句。

另请参阅

启用 ORM 的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_save_objects()

method close() → None

关闭此 Session 使用的事务资源和 ORM 对象。

代表 scoped_session 类的 Session 类的代理。

这会清除与此Session关联的所有 ORM 对象,结束进行中的任何事务,并释放此Session本身从关联的Engine对象中签出的任何Connection对象。然后,操作会使Session处于可以再次使用的状态。

提示

在默认运行模式下,Session.close()方法不会阻止使用该 SessionSession本身实际上并没有明确的“关闭”状态; 它只是表示Session将释放所有数据库连接和 ORM 对象。

将参数Session.close_resets_only设置为False将使close最终化,这意味着对会话的任何进一步操作都将被禁止。

从版本 1.4 开始:Session.close()方法不会立即创建新的SessionTransaction对象; 只有在再次为数据库操作使用Session时,才会创建新的SessionTransaction

请参阅

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.reset() - 一种行为类似于带有参数Session.close_resets_only设置为Trueclose()的方法。

classmethod close_all() → None

关闭所有内存中的会话。

代表scoped_session类为Session类进行了代理。

自版本 1.3 起不推荐使用:Session.close_all()方法已弃用,并将在将来的版本中删除。请参阅close_all_sessions()

method commit() → None

刷新待处理更改并提交当前事务。

代表scoped_session类的Session类的代理。

当 COMMIT 操作完成时,所有对象都将被完全过期,擦除其内部内容,在下次访问对象时将自动重新加载。在此期间,这些对象处于过期状态,如果它们从Session中分离出来,则将无法正常工作。此外,使用基于 asyncio 的 API 时不支持此重新加载操作。Session.expire_on_commit参数可用于禁用此行为。

Session没有正在进行的事务时,表示自上次调用Session.commit()以来在此Session上没有调用操作,该方法将开始并提交一个仅内部使用的“逻辑”事务,通常不会影响数据库,除非检测到待冲洗的更改,但仍将调用事件处理程序和对象过期规则。

最外层的数据库事务无条件提交,自动释放任何正在生效的 SAVEPOINT。

另请参见

提交

事务管理

在使用 AsyncSession 时防止隐式 IO

method configure(**kwargs: Any) → None

重新配置由此scoped_session使用的sessionmaker

参见 sessionmaker.configure()

method connection(bind_arguments: _BindArguments | None = None, execution_options: CoreExecuteOptionsParameter | None = None) → Connection

返回与此Session对象的事务状态对应的Connection对象。

代表scoped_session类的Session类的代理。

返回当前事务对应的Connection,或者如果没有进行事务,则开始新事务并返回Connection(请注意,在发出第一条 SQL 语句之前,与 DBAPI 之间不会建立事务状态)。

多绑定或未绑定的Session对象中的歧义可以通过任何可选关键字参数来解决。最终,通过使用get_bind()方法进行解决。

参数:

  • bind_arguments – 绑定参数字典。可能包括“mapper”,“bind”,“clause”,其他传递给Session.get_bind()的自定义参数。

  • execution_options

    执行选项字典,将在首次获得连接时传递给Connection.execution_options()仅在首次获得连接时。如果连接已经存在于Session中,则发出警告并忽略参数。

    另请参阅

    设置事务隔离级别/DBAPI AUTOCOMMIT

method delete(instance: object) → None

将实例标记为已删除。

代表scoped_session类的Session类的代理。

当传递时,假定对象为持久或分离状态;在调用该方法之后,对象将保持持久状态,直到下一个刷新发生。在此期间,对象还将是Session.deleted集合的成员。

下一次刷新发生时,对象将移动到删除状态,表示在当前事务中为其行发出了DELETE语句。当事务成功提交时,删除的对象将移动到分离状态,并且不再存在于此Session中。

另请参阅

删除 - 在使用会话的基础知识

attribute deleted

在此Session中标记为“已删除”的所有实例的集合

代理了scoped_session类,代表Session类。

attribute dirty

被视为脏的所有持久实例的集合。

代理了scoped_session类,代表Session类。

例如:

some_mapped_object in session.dirty

当实例被修改但未被删除时被视为脏。

请注意,此“脏”计算是“乐观”的;大多数属性设置或集合修改操作都会将实例标记为“脏”,并将其放入此集合中,即使属性的值没有净变化。在刷新时,将每个属性的值与其先前保存的值进行比较,如果没有净变化,则不会发生 SQL 操作(这是一个更昂贵的操作,因此只在刷新时执行)。

要检查实例是否对其属性具有可操作的净变化,请使用Session.is_modified()方法。

method execute(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, _parent_execute_state: Any | None = None, _add_event: Any | None = None) → Result[Any]

执行 SQL 表达式构造。

代理了scoped_session类,代表Session类。

返回一个表示语句执行结果的Result对象。

例如:

from sqlalchemy import select
result = session.execute(
    select(User).where(User.id == 5)
)

Session.execute()的 API 合同与Connection.execute()类似,是Connection的 2.0 风格版本。

从版本 1.4 开始:当使用 2.0 风格 ORM 使用时,Session.execute()方法现在是 ORM 语句执行的主要点。

参数:

  • statement – 可执行的语句(即Executable表达式,如select())。

  • params – 可选的字典,或包含绑定参数值的字典列表。如果是单个字典,则执行单行;如果是字典列表,则会触发“executemany”。每个字典中的键必须与语句中存在的参数名相对应。

  • execution_options

    可选的执行选项字典,将与语句执行关联。该字典可以提供 Connection.execution_options() 接受的选项子集,并且还可以提供仅在 ORM 上下文中理解的其他选项。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments – 用于确定绑定的其他参数字典。可能包括“mapper”、“bind”或其他自定义参数。此字典的内容将传递给 Session.get_bind() 方法。

返回:

一个 Result 对象。

method expire(instance: object, attribute_names: Iterable[str] | None = None) → None

使实例上的属性过期。

代表 scoped_session 类,代理 Session 类。

将实例的属性标记为过期。当下一次访问已过期的属性时,将向 Session 对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与该事务中先前读取的相同值,而不管该事务之外的数据库状态的变化。

同时使Session中的所有对象过期,可使用 Session.expire_all() 方法。

当调用 Session.rollback()Session.commit() 方法时,Session 对象的默认行为是使所有状态过期,以便为新事务加载新状态。因此,仅在当前事务中发出了非 ORM SQL 语句的情况下调用 Session.expire() 才有意义。

参数:

  • instance – 要刷新的实例。

  • attribute_names – 可选的字符串属性名称列表,指示要过期的属性子集。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expire_all() → None

使本 Session 中的所有持久化实例过期。

代理了 scoped_session 类的代表 Session 类。

下次访问持久化实例上的任何属性时,将使用 Session 对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与之前在同一事务中读取的相同值,而不管该事务之外的数据库状态是否发生变化。

要使单个对象以及这些对象上的单个属性过期,请使用 Session.expire()

当调用 Session.rollback()Session.commit() 方法时,Session 对象的默认行为是使所有状态过期,以便为新事务加载新状态。因此,通常情况下不需要调用 Session.expire_all(),假设事务是隔离的。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expunge(instance: object) → None

从此 Session 中删除实例。

代理了 scoped_session 类的代表 Session 类。

这将释放对实例的所有内部引用。将根据 expunge 级联规则应用级联。

method expunge_all() → None

从此 Session 中删除所有对象实例。

代理了 scoped_session 类的代表 Session 类。

这相当于在此 Session 中的所有对象上调用 expunge(obj)

method flush(objects: Sequence[Any] | None = None) → None

将所有对象更改刷新到数据库。

代表 scoped_session 类,为 Session 类代理。

将所有待处理的对象创建、删除和修改写入数据库,作为 INSERT、DELETE、UPDATE 等操作。操作会自动按照 Session 的工作单元依赖解决器进行排序。

数据库操作将在当前事务上下文中发出,并且不会影响事务的状态,除非发生错误,此时整个事务将回滚。您可以在事务中随意刷新(flush())以将更改从 Python 移动到数据库的事务缓冲区。

参数:

对象 -

可选;将刷新操作限制为仅对给定集合中存在的元素进行操作。

此功能仅适用于极少数情况,特定对象可能需要在完全执行 flush() 之前进行操作。不适用于一般用途。

method get(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O | None

返回基于给定主键标识符的实例,如果找不到,则返回 None

代表 scoped_session 类,为 Session 类代理。

例如:

my_user = session.get(User, 5)

some_object = session.get(VersionedFoo, (5, 10))

some_object = session.get(
    VersionedFoo,
    {"id": 5, "version_id": 10}
)

版本 1.4 中新增:新增 Session.get(),它从现在遗留的 Query.get() 方法中移动而来。

Session.get() 特殊之处在于它直接提供对 Session 的标识映射的访问。如果给定的主键标识符存在于本地标识映射中,则直接从此集合返回对象,而不发出 SQL,除非对象已标记为完全过期。如果不存在,则执行 SELECT 以定位对象。

Session.get() 方法也会检查对象是否存在于标识映射中并标记为过期 - 还会发出 SELECT 来刷新对象以及确保行仍然存在。如果不存在,则会引发 ObjectDeletedError

参数:

  • entity - 表示要加载的实体类型的映射类或 Mapper

  • ident -

    表示主键的标量、元组或字典。对于复合(例如多列)主键,应传递元组或字典。

    对于单列主键,标量调用形式通常是最方便的。如果行的主键值为“5”,则调用如下所示:

    my_object = session.get(SomeClass, 5)
    

    元组形式包含主键值,通常按照它们对应于映射的Table对象的主键列的顺序排列,或者如果使用了Mapper.primary_key配置参数,则按照该参数使用的顺序排列。例如,如果行的主键由整数数字“5, 10”表示,则调用将如下所示:

    my_object = session.get(SomeClass, (5, 10))
    

    字典形式应包含键,这些键对应于主键的每个元素的映射属性名称。如果映射类具有idversion_id作为存储对象主键值的属性,则调用如下所示:

    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
    
  • options – 可选的加载器选项序列,如果发出了查询,则将应用于该查询。

  • populate_existing – 导致该方法无条件发出 SQL 查询,并使用新加载的数据刷新对象,而不管对象是否已存在。

  • with_for_update – 可选的布尔值True,表示应使用 FOR UPDATE,或者可以是一个包含标志的字典,用于指示用于 SELECT 的更具体的 FOR UPDATE 标志集;标志应与Query.with_for_update()的参数匹配。取代Session.refresh.lockmode参数。

  • execution_options

    可选的执行选项字典,如果发出了查询,则将与查询执行关联起来。此字典可以提供Connection.execution_options()接受的选项子集,并且还可以提供仅在 ORM 上下文中理解的其他选项。

    1.4.29 版本中的新功能。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments

    用于确定绑定的其他参数的字典。可能包括“mapper”、“bind”或其他自定义参数。此字典的内容传递给 Session.get_bind() 方法。

返回:

对象实例,或None

method get_bind(mapper: _EntityBindKey[_O] | None = None, *, clause: ClauseElement | None = None, bind: _SessionBind | None = None, _sa_skip_events: bool | None = None, _sa_skip_for_implicit_returning: bool = False, **kw: Any) → Engine | Connection

返回此Session绑定的“bind”。

代理给scoped_session类的Session类。

“bind”通常是Engine的实例,除非Session已经明确地直接绑定到Connection的情况除外。

对于多重绑定或未绑定的Session,使用mapperclause参数来确定要返回的适当绑定。

请注意,通常在通过 ORM 操作调用Session.get_bind()时,会出现“mapper”参数,例如Session.query()中的每个单独的 INSERT/UPDATE/DELETE 操作,Session.flush()调用等。

解析顺序为:

  1. 如果提供了映射器并且Session.binds存在,则首先基于正在使用的映射器,然后基于正在使用的映射类,最后基于映射类的__mro__中存在的任何基类来定位绑定,从更具体的超类到更一般的超类。

  2. 如果提供了 clause 并且存在Session.binds,则基于Session.binds中存在的给定 clause 中的Table对象来定位绑定。

  3. 如果存在Session.binds,则返回该绑定。

  4. 如果提供了 clause,则尝试返回与最终与 clause 相关联的MetaData相关联的绑定。

  5. 如果提供了映射器,则尝试返回与映射器映射到的Table或其他可选择对象最终相关联的MetaData相关联的绑定。

  6. 无法找到绑定时,引发UnboundExecutionError

请注意,Session.get_bind()方法可以在Session的用户定义子类上被重写,以提供任何类型的绑定解析方案。请参阅 Custom Vertical Partitioning 中的示例。

参数:

  • mapper – 可选的映射类或对应的Mapper实例。绑定可以首先通过查看与此Session关联的“binds”映射,其次通过查看与此Mapper映射到的Table相关联的MetaData来派生绑定。

  • clause – 一个ClauseElement(即select(), text()等)。如果不存在mapper参数或无法生成绑定,则将搜索给定的表达式构造,通常是与绑定的MetaData关联的Table

另请参见

分区策略(例如每个会话多个数据库后端)

Session.binds

Session.bind_mapper()

Session.bind_table()

method get_one(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O

根据给定的主键标识符返回确切的一个实例,如果未找到则引发异常。

代理为scoped_session类代表Session类。

如果查询未选择任何行,则引发sqlalchemy.orm.exc.NoResultFound异常。

要详细了解参数的文档,请参阅方法Session.get()

版本 2.0.22 中的新功能。

返回:

对象实例。

另请参见

Session.get() - 相同的方法,但代替

如果找不到提供的主键的行,则返回None

classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

返回一个身份键。

代理为scoped_session类代表Session类。

这是identity_key()的别名。

attribute identity_map

代理scoped_session类的Session.identity_map属性。

attribute info

用户可修改的字典。

代理scoped_session类的Session类。

此字典的初始值可以使用Session构造函数或sessionmaker构造函数或工厂方法的info参数进行填充。此处的字典始终局限于此Session并且可以独立于所有其他Session对象进行修改。

attribute is_active

如果此Session不处于“部分回滚”状态,则返回 True。

代理scoped_session类的Session类。

在 1.4 版本中更改:Session不再立即开始新的事务,因此当首次实例化Session时,此属性将为 False。

“部分回滚”状态通常表示Session的刷新过程失败,并且必须发出Session.rollback()方法以完全回滚事务。

如果此Session根本不在事务中,则第一次使用时会自动开始,因此在这种情况下Session.is_active将返回 True。

否则,如果此Session在事务中,并且该事务尚未在内部回滚,则Session.is_active也将返回 True。

另请参阅

“由于在刷新期间发生的先前异常,此会话的事务已回滚。”(或类似)

Session.in_transaction()

method is_modified(instance: object, include_collections: bool = True) → bool

如果给定的实例具有本地修改的属性,则返回True

代表scoped_session类的Session类的代理。

此方法检索实例上每个受控属性的历史记录,并将当前值与其以前提交的值(如果有)进行比较。

实际上,这是一个更昂贵且更准确的版本,用于检查给定实例是否在Session.dirty集合中;对于每个属性的净“脏”状态进行了全面测试。

例如:

return session.is_modified(someobject)

此方法有一些注意事项:

  • 当使用此方法测试时,Session.dirty集合中存在的实例可能报告False。这是因为该对象可能已通过属性突变接收到更改事件,从而将其放置在Session.dirty中,但最终状态与从数据库加载的状态相同,在此处没有净更改。

  • 当新值被应用时,标量属性可能未记录先前设置的值,如果属性在新值接收时未加载或过期,则在这些情况下,即使最终没有对其数据库值进行净更改,也假定该属性发生了更改。大多数情况下,当发生设置事件时,SQLAlchemy 不需要“旧”值,因此,如果旧值不存在,则跳过 SQL 调用的开销,基于假设更新标量值通常是必要的,而在那些很少的情况下它不是,平均而言比发出防御性 SELECT 要便宜。

    当属性容器的active_history标志设置为True时,将无条件获取“旧”值,仅在发生设置时。通常为主键属性和非简单多对一的标量对象引用设置此标志。要为任意映射列设置此标志,请使用column_property()中的active_history参数。

参数:

  • instance - 要测试是否存在未决更改的映射实例。

  • include_collections - 表示是否应在操作中包含多值集合。将其设置为False是一种检测仅基于本地列的属性(即标量列或多对一外键)的方法,这些属性在刷新此实例时将导致 UPDATE。

method merge(instance: _O, *, load: bool = True, options: Sequence[ORMOption] | None = None) → _O

将给定实例的状态复制到此Session中的相应实例。

代理Session类,代表scoped_session类。

Session.merge()检查源实例的主键属性,并尝试将其与会话中具有相同主键的实例进行协调。如果在本地找不到,它会尝试根据主键从数据库加载对象,如果找不到任何对象,则创建一个新实例。然后将源实例上的每个属性的状态复制到目标实例。然后,该方法将返回结果目标实例;原始源实例保持不变,并且如果尚未与Session关联,则保持不相关。

如果关联映射了cascade="merge",此操作会级联到关联的实例。

有关合并的详细讨论,请参阅合并。

参数:

  • instance – 要合并的实例。

  • load

    当为 False 时,merge()切换到“高性能”模式,导致它放弃发出历史事件以及所有数据库访问。此标志用于将对象图转移到来自第二级缓存的Session中,或者将刚加载的对象转移到由工作线程或进程拥有的Session中,而无需重新查询数据库。

    load=False用例添加了这样的警告,即给定对象必须处于“干净”状态,即没有待刷新的更改 - 即使传入对象与任何Session都没有关联。这是为了当合并操作填充本地属性并级联到相关对象和集合时,值可以按原样“盖印”到目标对象上,而不生成任何历史或属性事件,并且无需将传入数据与可能未加载的任何现有相关对象或集合进行协调。来自load=False的结果对象始终作为“干净”生成,因此只有给定的对象也应该“干净”,否则这表明方法的错误使用。

  • options

    在合并操作加载对象的现有版本时,将应用到 Session.get() 方法的可选加载器选项序列。

    新版本 1.4.24 中新增。

另请参阅

make_transient_to_detached() - 提供了将单个对象“合并”到 Session 中的替代方法

attribute new

在此 Session 中标记为“新”的所有实例的集合。

代表 scoped_session 类而为 Session 类代理。

attribute no_autoflush

返回一个上下文管理器,用于禁用自动提交。

代表 scoped_session 类而为 Session 类代理。

例如:

with session.no_autoflush:

    some_object = SomeClass()
    session.add(some_object)
    # won't autoflush
    some_object.related_thing = session.query(SomeRelated).first()

with: 块中进行的操作将不会受到在查询访问时发生的刷新的影响。当初始化涉及现有数据库查询的一系列对象时,尚未完成的对象不应立即被刷新时,这将很有用。

classmethod object_session(instance: object) → Session | None

返回对象所属的 Session

代表 scoped_session 类而为 Session 类代理。

这是 object_session() 的别名。

method query(*entities: _ColumnsClauseArgument[Any], **kwargs: Any) → Query[Any]

返回一个新的与此 Session 对应的 Query 对象。

代表 scoped_session 类而为 Session 类代理。

请注意,Query 对象在 SQLAlchemy 2.0 中已被标记为遗留;现在使用 select() 构造 ORM 查询。

另请参阅

SQLAlchemy 统一教程

ORM 查询指南

遗留查询 API - 遗留 API 文档

method query_property(query_cls: Type[Query[_T]] | None = None) → QueryPropertyDescriptor

返回一个类属性,当调用时,该属性会针对类和当前 Session 生成一个遗留 Query 对象。

遗留特性

scoped_session.query_property() 访问器是特定于传统的 Query 对象的,不被视为 2.0 风格 ORM 使用的一部分。

例如:

from sqlalchemy.orm import QueryPropertyDescriptor
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker

Session = scoped_session(sessionmaker())

class MyClass:
    query: QueryPropertyDescriptor = Session.query_property()

# after mappers are defined
result = MyClass.query.filter(MyClass.name=='foo').all()

默认情况下,生成会话配置的查询类的实例。要覆盖并使用自定义实现,请提供一个 query_cls 可调用对象。将以类的映射器作为位置参数和一个会话关键字参数调用该可调用对象。

类上放置的查询属性数量没有限制。

method refresh(instance: object, attribute_names: Iterable[str] | None = None, with_for_update: ForUpdateParameter = None) → None

在给定实例上过期并刷新属性。

代理scoped_session 类的 Session 类。

选定的属性将首先过期,就像使用 Session.expire() 时一样;然后将向数据库发出 SELECT 语句,以使用当前事务中可用的当前值刷新列导向属性。

relationship() 导向属性如果已经在对象上急切加载,将立即被加载,使用与最初加载时相同的急切加载策略。

自 1.4 版开始:- Session.refresh() 方法也可以刷新急切加载的属性。

如果通常使用select(或“延迟”)加载器策略加载的 relationship() 导向属性也将加载,如果它们在 attribute_names 集合中明确命名,则使用 immediate 加载器策略发出 SELECT 语句加载该属性。如果惰性加载的关系未在 Session.refresh.attribute_names 中命名,则它们将保持为“惰性加载”属性,不会被隐式刷新。

从版本 2.0.4 开始更改:Session.refresh() 方法现在将刷新 relationship() 导向属性的惰性加载属性,对于那些在 Session.refresh.attribute_names 集合中明确命名的属性。

提示

虽然 Session.refresh() 方法能够刷新列和关系导向属性,但其主要重点是刷新单个实例上的本地列导向属性。对于更开放式的“刷新”功能,包括能够同时刷新多个对象的属性,并对关系加载器策略有明确控制的功能,请使用填充现有对象功能。

请注意,高度隔离的事务将返回与在同一事务中先前读取的相同值,而不考虑该事务之外数据库状态的更改。通常只在事务开始时刷新属性才有意义,在那时数据库行尚未被访问。

参数:

  • attribute_names – 可选。一个包含字符串属性名称的可迭代集合,指示要刷新的属性子集。

  • with_for_update – 可选布尔值 True 表示应该使用 FOR UPDATE,或者可以是一个包含标志的字典,指示应该使用更具体的 FOR UPDATE 标志集合进行 SELECT;标志应该与 Query.with_for_update() 的参数匹配。取代 Session.refresh.lockmode 参数。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.expire_all()

填充现有对象 - 允许任何 ORM 查询刷新对象,就像它们通常加载的方式一样。

method remove() → None

丢弃当前Session(如果存在)。

这将首先在当前Session上调用Session.close()方法,释放仍在保持的任何现有事务/连接资源;具体来说,事务将被回滚。然后丢弃Session。在同一范围内的下一次使用时,scoped_session将生成一个新的Session对象。

method reset() → None

关闭此Session使用的事务资源和 ORM 对象,将会重置会话到其初始状态。

代理scoped_session类代表Session类。

此方法提供了与Session.close()方法在历史上提供的相同的“仅重置”行为,其中Session的状态被重置,就像对象是全新的,准备好再次使用。对于将Session.close_resets_only设置为FalseSession对象,此方法可能会很有用,以便仍然可以使用“仅重置”行为。

版本 2.0.22 中的新功能。

另请参见

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.close() - 当参数Session.close_resets_only设置为False时,类似的方法还会阻止重复使用 Session。

method rollback() → None

回滚当前进行中的事务。

代理scoped_session类代表Session类。

如果没有进行中的事务,则此方���是一个透传。

该方法始终回滚顶层数据库事务,丢弃可能正在进行的任何嵌套事务。

另请参见

回滚

管理事务

method scalar(statement: Executable, params: _CoreSingleExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → Any

执行语句并返回标量结果。

代理scoped_session类代表Session类。

使用和参数与Session.execute()相同;返回结果是一个标量 Python 值。

method scalars(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → ScalarResult[Any]

执行语句并将结果作为标量返回。

代理scoped_session类代表Session类。

使用方法和参数与Session.execute()相同;返回结果是一个ScalarResult过滤对象,它将返回单个元素而不是Row对象。

返回:

一个ScalarResult对象

新版本 1.4.24 中新增:Session.scalars()

新版本 1.4.26 中新增:scoped_session.scalars()

另请参见

选择 ORM 实体 - 将Session.execute()的行为与Session.scalars()进行对比

attribute session_factory: sessionmaker[_S]

提供给 init 的 session_factory 存储在此属性中,可以在以后访问。当需要新的非范围化的Session时,这可能会有用。

class sqlalchemy.util.ScopedRegistry

一个可以根据“scope”函数存储单个类的一个或多个实例的注册表。

此对象实现了__call__作为“getter”,因此通过调用myregistry()将返回当前范围内的包含对象。

参数:

  • createfunc – 返回要放置在注册表中的新对象的可调用函数

  • scopefunc – 一个可调用函数,将返回一个键以存储/检索对象。

成员

init(), clear(), has(), set()

类签名

sqlalchemy.util.ScopedRegistrytyping.Generic

method __init__(createfunc: Callable[[], _T], scopefunc: Callable[[], Any])

构造一个新的ScopedRegistry

参数:

  • createfunc – 如果当前范围中不存在,则生成新值的创建函数。

  • scopefunc – 一个返回表示当前范围的可哈希令牌的函数(例如,当前线程标识符)。

method clear() → None

清除当前范围(如果有)。

method has() → bool

如果当前范围中存在对象,则返回 True。

method set(obj: _T) → None

设置当前范围的值。

class sqlalchemy.util.ThreadLocalRegistry

使用threading.local()变量进行存储的ScopedRegistry

类签名

sqlalchemy.util.ThreadLocalRegistrysqlalchemy.util.ScopedRegistry

class sqlalchemy.orm.QueryPropertyDescriptor

描述应用于类级别scoped_session.query_property()属性的类型。

自 2.0.5 版本新增。

类签名

sqlalchemy.orm.QueryPropertyDescriptortyping_extensions.Protocol

使用事件跟踪查询、对象和会话更改

原文:docs.sqlalchemy.org/en/20/orm/session_events.html

SQLAlchemy 特色是一个广泛的事件监听系统,贯穿于核心和 ORM 中。在 ORM 中,有各种各样的事件监听器钩子,这些钩子在 ORM 事件的 API 级别有文档记录。这些事件的集合多年来已经增长,包括许多非常有用的新事件,以及一些曾经不那么相关的旧事件。本节将尝试介绍主要的事件钩子以及它们何时可能被使用。

执行事件

从版本 1.4 新增:现在Session提供了一个单一全面的钩子,用于拦截 ORM 代表进行的所有 SELECT 语句,以及大量的 UPDATE 和 DELETE 语句。这个钩子取代了以前的QueryEvents.before_compile()事件以及QueryEvents.before_compile_update()QueryEvents.before_compile_delete()

Session提供了一个全面的系统,通过该系统,通过Session.execute()方法调用的所有查询,包括由Query发出的所有 SELECT 语句以及代表列和关系加载器发出的所有 SELECT 语句,都可以被拦截和修改。该系统使用SessionEvents.do_orm_execute()事件钩子以及ORMExecuteState对象来表示事件状态。

基本查询拦截

SessionEvents.do_orm_execute() 首先对查询的任何拦截都是有用的,包括由 Query 以 1.x 风格 发出的查询,以及当 ORM 启用的 2.0 风格 下传递给 Session.execute()select()update()delete() 构造。ORMExecuteState 构造提供了访问器,以允许修改语句、参数和选项:

Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if orm_execute_state.is_select:
        # add populate_existing for all SELECT statements

        orm_execute_state.update_execution_options(populate_existing=True)

        # check if the SELECT is against a certain entity and add an
        # ORDER BY if so
        col_descriptions = orm_execute_state.statement.column_descriptions

        if col_descriptions[0]["entity"] is MyEntity:
            orm_execute_state.statement = statement.order_by(MyEntity.name)

上述示例说明了对 SELECT 语句进行的一些简单修改。在这个层次上,SessionEvents.do_orm_execute() 事件钩子旨在取代之前使用的 QueryEvents.before_compile() 事件,该事件对各种加载器的各种类型并不一致地触发;此外,QueryEvents.before_compile() 仅适用于与 Query 的 1.x 风格 一起使用,而不适用于 2.0 风格 下使用 Session.execute()

添加全局的 WHERE / ON 条件

最常请求的查询扩展功能之一是向所有查询中的所有实体添加 WHERE 条件的能力。这可以通过使用 with_loader_criteria() 查询选项来实现,该选项可以单独使用,也可以在 SessionEvents.do_orm_execute() 事件中使用:

from sqlalchemy.orm import with_loader_criteria

Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(MyEntity.public == True)
        )

在上述内容中,为所有 SELECT 语句添加了一个选项,该选项将限制针对MyEntity的所有查询以在public == True上进行过滤。该条件将应用于立即查询范围内该类的所有加载。with_loader_criteria()选项默认情况下还会自动传播到关系加载程序,这将应用于后续的关系加载,包括惰性加载,selectinloads 等。

对于一系列具有某些共同列结构的类,如果使用声明性混合来组合类,那么混合类本身可以与with_loader_criteria()选项结合使用,通过使用 Python lambda 来使用。 Python lambda 将针对与条件匹配的特定实体在查询编译时调用。假设一系列基于名为HasTimestamp的混合物的类:

import datetime

class HasTimestamp:
    timestamp = mapped_column(DateTime, default=datetime.datetime.now)

class SomeEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

class SomeOtherEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

上述类SomeEntitySomeOtherEntity将分别具有一个timestamp列,其默认值为当前日期和时间。可以使用事件拦截所有扩展自HasTimestamp并过滤其timestamp列的对象,使其日期不晚于一个月前:

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        one_month_ago = datetime.datetime.today() - datetime.timedelta(months=1)

        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(
                HasTimestamp,
                lambda cls: cls.timestamp >= one_month_ago,
                include_aliases=True,
            )
        )

警告

在调用with_loader_criteria()时使用 lambda 仅被调用一次每个唯一类。在此 lambda 内部不应调用自定义函数。请参阅使用 Lambda 将重要的速度增益添加到语句生成以获取“lambda SQL”功能的概述,该功能仅用于高级用途。

另请参阅

ORM 查询事件 - 包括上述with_loader_criteria()配方的工作示例。 ### 重新执行语句

深度炼金术

语句重新执行功能涉及稍微复杂的递归序列,并旨在解决将 SQL 语句的执行重新路由到各种非 SQL 上下文的相当困难的问题。下面链接的“狗窝缓存”和“水平分片”的双例应该用作指导,以确定何时适合使用此相当高级的功能。

ORMExecuteState能够控制给定语句的执行;这包括能力要么根本不调用语句,而是返回一个从缓存中检索到的预先构建的结果集,要么调用相同的语句多次,每次使用不同的状态,例如对多个数据库连接调用它,然后在内存中合并结果。这两种高级模式都在 SQLAlchemy 的示例套件中有详细说明。

SessionEvents.do_orm_execute()事件钩子内部时,可以使用ORMExecuteState.invoke_statement()方法来使用新的嵌套调用Session.execute()来调用语句,这将抢占当前正在进行的执行的后续处理,而是返回内部执行返回的Result。因此,在此过程中已调用的SessionEvents.do_orm_execute()钩子的事件处理程序也将在此嵌套调用中被跳过。

ORMExecuteState.invoke_statement()方法返回一个Result对象;然后该对象具有冻结为可缓存格式和解冻为新的Result对象的能力,以及将其数据与其他Result对象的数据合并的能力。

例如,使用SessionEvents.do_orm_execute()来实现缓存:

from sqlalchemy.orm import loading

cache = {}

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if "my_cache_key" in orm_execute_state.execution_options:
        cache_key = orm_execute_state.execution_options["my_cache_key"]

        if cache_key in cache:
            frozen_result = cache[cache_key]
        else:
            frozen_result = orm_execute_state.invoke_statement().freeze()
            cache[cache_key] = frozen_result

        return loading.merge_frozen_result(
            orm_execute_state.session,
            orm_execute_state.statement,
            frozen_result,
            load=False,
        )

当上述钩子生效时,使用缓存的示例如下:

stmt = (
    select(User).where(User.name == "sandy").execution_options(my_cache_key="key_sandy")
)

result = session.execute(stmt)

上面的例子中,自定义的执行选项被传递给Select.execution_options(),以建立一个“缓存键”,然后该键将被SessionEvents.do_orm_execute()钩子拦截。然后,这个缓存键将与可能存在于缓存中的FrozenResult对象进行匹配,并且如果存在,则重新使用该对象。该示例利用了Result.freeze()方法来“冻结”一个包含 ORM 结果的Result对象,以便它可以被存储在缓存中并多次使用。为了从“冻结”结果中返回一个活动结果,使用merge_frozen_result()函数将结果对象中的“冻结”数据合并到当前会话中。

上面的例子在 Dogpile 缓存中作为一个完整的例子实现。

ORMExecuteState.invoke_statement()方法也可以被多次调用,传递不同的信息给ORMExecuteState.invoke_statement.bind_arguments参数,以便Session每次都使用不同的Engine对象。这将每次返回一个不同的Result对象;这些结果可以使用Result.merge()方法合并在一起。这是水平分片扩展所采用的技术;请查看源代码以熟悉它。

另请参阅

Dogpile 缓存

水平分片 ## 持久化事件

可能是最广泛使用的一系列事件是“持久化”事件,它们对应于刷新过程。刷新是所有关于待处理对象更改的决定都会被做出,并以 INSERT、UPDATE 和 DELETE 语句的形式发送到数据库的地方。

before_flush()

SessionEvents.before_flush() 钩子是当应用程序希望在提交刷新时确保额外的持久性更改被执行时最常用的事件。 使用 SessionEvents.before_flush() 来验证对象的状态并在持久化之前组合其他对象和引用。在此事件中,可以安全地操纵会话的状态,即可以附加新对象,删除对象,并且可以自由更改对象上的单个属性,这些更改将在事件钩子完成时被纳入刷新过程中。

典型的 SessionEvents.before_flush() 钩子将被指示扫描集合 Session.newSession.dirtySession.deleted,以查找将要发生更改的对象。

有关 SessionEvents.before_flush() 的示例,请参见具有历史表的版本控制和使用时间行进行版本控制等示例。

after_flush()

SessionEvents.after_flush() 钩子在刷新过程的 SQL 被生成之后,但在被刷新的对象状态被更改之前调用。也就是说,您仍然可以检查 Session.newSession.dirtySession.deleted 集合,以查看刚刷新的内容,并且还可以使用像 AttributeState 这样的历史跟踪功能来查看刚刚持久化的更改。在 SessionEvents.after_flush() 事件中,可以根据观察到的更改向数据库发送额外的 SQL。

after_flush_postexec()

SessionEvents.after_flush_postexec()SessionEvents.after_flush() 之后不久调用,但是在对象状态已经被修改以考虑刚刚发生的刷新之后调用。Session.newSession.dirtySession.deleted 集合通常在此时完全为空。使用 SessionEvents.after_flush_postexec() 检查最终对象的标识映射,并可能发出附加的 SQL。在这个钩子中,有能力对对象进行新的更改,这意味着 Session 再次进入“脏”状态;Session 的机制会导致如果在此钩子中检测到新的更改,那么再次刷新如果在 Session.commit() 的上下文中调用了刷新;否则,待定更改将作为下一个正常刷新的一部分进行捆绑。当钩子在 Session.commit() 中检测到新的更改时,一个计数器确保在每次调用时,如果 SessionEvents.after_flush_postexec() 钩子持续添加新状态以刷新,则此方面的无限循环在 100 次迭代后停止。

映射器级刷新事件

除了刷新级别的钩子外,还有一套更精细的钩子,这些钩子更加细致,因为它们是基于每个对象调用的,并且根据刷新过程中的 INSERT、UPDATE 或 DELETE 进行分组。这些是映射器持久性钩子,它们也非常受欢迎,但是需要更加谨慎地对待这些事件,因为它们在已经进行的刷新过程的上下文中进行;在这里进行许多操作是不安全的。

这些事件是:

  • MapperEvents.before_insert()

  • MapperEvents.after_insert()

  • MapperEvents.before_update()

  • MapperEvents.after_update()

  • MapperEvents.before_delete()

  • MapperEvents.after_delete()

注意

需要注意的是,这些事件仅适用于会话刷新操作,而不适用于在 ORM-启用的 INSERT、UPDATE 和 DELETE 语句中描述的 ORM 级别的 INSERT/UPDATE/DELETE 功能。要拦截 ORM 级别的 DML,请使用SessionEvents.do_orm_execute()事件。

每个事件都会传递Mapper、映射对象本身以及用于发出 INSERT、UPDATE 或 DELETE 语句的Connection。这些事件的吸引力显而易见,因为如果应用程序想要将某些活动绑定到特定类型的对象在 INSERT 时被持久化的时间,钩子就非常具体;不像SessionEvents.before_flush()事件,不需要搜索诸如Session.new之类的集合以找到目标。然而,当调用这些事件时,表示完整列表的刷新计划,即将发出的每个单独的 INSERT、UPDATE、DELETE 语句已经已经决定,在这个阶段不允许进行任何更改。因此,甚至对于给定对象的其他属性也只能进行局部更改。对对象或其他对象的任何其他更改将影响Session的状态,这将导致其无法正常运行。

在这些映射器级持久性事件中不支持的操作包括:

  • Session.add()

  • Session.delete()

  • 映射集合追加、添加、移除、删除、丢弃等操作。

  • 映射关系属性设置/删除事件,即someobject.related = someotherobject

传递Connection的原因是鼓励在这里进行简单的 SQL 操作,直接在Connection上进行,例如在日志表中递增计数器或插入额外行。

也有许多每个对象操作根本不需要在刷新事件中处理。最常见的替代方法是在对象的__init__()方法中简单地建立额外的状态,例如创建要与新对象关联的其他对象。使用 Simple Validators 中描述的验证器是另一种方法;这些函数可以拦截属性的更改,并在响应属性更改时在目标对象上建立额外的状态更改。使用这两种方法,对象在到达刷新步骤之前就处于正确的状态。## 对象生命周期事件

事件的另一个用例是跟踪对象的生命周期。这指的是首次介绍于 Quickie Intro to Object States 的状态。

所有上述状态都可以完全通过事件进行跟踪。每个事件代表着一个独立的状态转换,意味着起始状态和目标状态都是被跟踪的一部分。除了初始的瞬态事件之外,所有事件都是以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)

瞬态

所有映射对象在首次构建时都是瞬态的。在这种状态下,对象独立存在,不与任何Session关联。对于这种初始状态,没有特定的“转换”事件,因为没有Session,但是如果想要拦截任何瞬态对象被创建时,InstanceEvents.init()方法可能是最好的事件。此事件应用于特定类或超类。例如,要拦截特定声明基类的所有新对象:

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import event

class Base(DeclarativeBase):
    pass

@event.listens_for(Base, "init", propagate=True)
def intercept_init(instance, args, kwargs):
    print("new transient: %s" % instance)

瞬态到待定

当瞬态对象首次通过Session.add()Session.add_all()方法与Session关联时,瞬态对象变为待定。对象也可能作为引用对象的“级联”结果成为Session的一部分,该引用对象是显式添加的。使用SessionEvents.transient_to_pending()事件检测瞬态到待定的转换过程:

@event.listens_for(sessionmaker, "transient_to_pending")
def intercept_transient_to_pending(session, object_):
    print("transient to pending: %s" % object_)

待定到持久化

当一个刷新操作进行并且为实例执行 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_)

待定到瞬态

如果在待定对象被刷新之前调用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() 方法,持久化对象可以恢复到瞬时状态。在 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_)

持久化到删除

当在 flush 过程中从数据库中删除了标记为删除的对象时,持久化对象进入 deleted 状态。请注意,这调用 Session.delete() 方法删除目标对象时并不相同Session.delete() 方法只是将对象标记为删除;直到 flush 进行之后才会发出实际的 DELETE 语句。在 flush 进行之后,目标对象的“deleted”状态才存在。

在“deleted”状态中,对象与 Session 仅有轻微关联。它既不在标识映射中,也不在指示其曾待删除的 Session.deleted 集合中。

从“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_)

已删除到已分离

当会话的事务提交时,已删除对象将变为分离。在调用 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 访问器。

持久到分离

当对象与 Session 解除关联时,通过 Session.expunge()Session.expunge_all()Session.close() 方法,持久对象将变为分离状态。

注意

如果一个对象的拥有者 Session 被应用程序解除引用并由于垃圾回收而被丢弃,该对象也可能会隐式分离。在这种情况下,不会发出任何事件

使用 SessionEvents.persistent_to_detached() 事件跟踪对象从持久状态转为分离状态:

@event.listens_for(sessionmaker, "persistent_to_detached")
def intercept_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 intercept_detached_to_persistent(session, object_):
    print("object became persistent again: %s" % object_)

已删除到持久

当删除对象在其所在的事务被回滚时,可以将其恢复为持久状态,使用Session.rollback()方法回滚。使用SessionEvents.deleted_to_persistent()事件跟踪将删除的对象移回持久状态:

@event.listens_for(sessionmaker, "deleted_to_persistent")
def intercept_deleted_to_persistent(session, object_):
    print("deleted to persistent: %s" % object_)
```  ## 事务事件

事务事件允许应用在`Session`级别上发生事务边界时收到通知,以及当`Session`更改`Connection`对象上的事务状态时。

+   `SessionEvents.after_transaction_create()`,`SessionEvents.after_transaction_end()` - 这些事件跟踪`Session`的逻辑事务范围,不特定于单个数据库连接。这些事件旨在帮助集成事务跟踪系统,如`zope.sqlalchemy`。当应用程序需要将某些外部范围与`Session`的事务范围对齐时,请使用这些事件。这些挂钩反映了`Session`的“嵌套”事务行为,因为它们跟踪逻辑“子事务”以及“嵌套”(例如,SAVEPOINT)事务。

+   `SessionEvents.before_commit()`、`SessionEvents.after_commit()`、`SessionEvents.after_begin()`、`SessionEvents.after_rollback()`、`SessionEvents.after_soft_rollback()` - 这些事件允许从数据库连接的角度跟踪事务事件。特别是`SessionEvents.after_begin()`是一个每个连接的事件;一个维护多个连接的`Session`将为每个连接在当前事务中使用时单独发出此事件。然后回滚和提交事件指的是 DBAPI 连接自身直接接收回滚或提交指令的时候。

## 属性更改事件

属性更改事件允许拦截对象上特定属性被修改的时机。这些事件包括`AttributeEvents.set()`、`AttributeEvents.append()`和`AttributeEvents.remove()`。这些事件非常有用,特别是对于每个对象的验证操作;然而,使用“验证器”钩子通常更加方便,它在幕后使用这些钩子;请参阅 Simple Validators 以了解背景信息。属性事件也是反向引用机制的基础。一个说明属性事件使用的示例在 Attribute Instrumentation 中。

## 执行事件

新版本 1.4 中新增:`Session`现在具有一个全面的钩子,旨在拦截所有代表 ORM 执行的 SELECT 语句以及批量 UPDATE 和 DELETE 语句。这个钩子取代了之前的`QueryEvents.before_compile()`事件以及`QueryEvents.before_compile_update()`和`QueryEvents.before_compile_delete()`。

`Session`具有一个全面的系统,通过该系统可以拦截和修改通过`Session.execute()`方法调用的所有查询,其中包括由`Query`发出的所有 SELECT 语句以及所有代表列和关系加载程序发出的 SELECT 语句。该系统利用了`SessionEvents.do_orm_execute()`事件钩子以及`ORMExecuteState`对象来表示事件状态。

### 基本查询拦截

`SessionEvents.do_orm_execute()`首先对查询的任何拦截都是有用的,这包括由`Query`发出的 1.x 风格以及当 ORM 启用的 2.0 风格的`select()`,`update()`或`delete()`构造被传递给`Session.execute()`时。`ORMExecuteState`构造提供了访问器,允许修改语句、参数和选项:

```py
Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if orm_execute_state.is_select:
        # add populate_existing for all SELECT statements

        orm_execute_state.update_execution_options(populate_existing=True)

        # check if the SELECT is against a certain entity and add an
        # ORDER BY if so
        col_descriptions = orm_execute_state.statement.column_descriptions

        if col_descriptions[0]["entity"] is MyEntity:
            orm_execute_state.statement = statement.order_by(MyEntity.name)

上面的示例说明了对 SELECT 语句的一些简单修改。在这个级别上,SessionEvents.do_orm_execute() 事件钩子旨在替换以前对各种加载器不一致触发的 QueryEvents.before_compile() 事件的使用;此外,QueryEvents.before_compile() 仅适用于 1.x 样式 与 Query 一起使用,并不适用于 2.0 样式 与 Session.execute() 一起使用。

添加全局 WHERE / ON 条件

最常请求的查询扩展功能之一是能够向所有查询中的所有实体添加 WHERE 条件。通过使用 with_loader_criteria() 查询选项,可以实现此目的,该选项可以单独使用,或者最好在 SessionEvents.do_orm_execute() 事件中使用:

from sqlalchemy.orm import with_loader_criteria

Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(MyEntity.public == True)
        )

上面,所有 SELECT 语句都添加了一个选项,将限制针对 MyEntity 的所有查询,以在 public == True 上进行过滤。这些条件将应用于立即查询范围内该类的所有加载。with_loader_criteria() 选项默认情况下也会自动传播到关系加载器,这将应用于后续的关系加载,包括延迟加载、selectinloads 等。

对于一系列具有某些共同列结构的类,如果这些类使用 declarative mixin 进行组合,那么 mixin 类本身可以与 with_loader_criteria() 选项结合使用,方法是使用 Python lambda。Python lambda 将在查询编译时针对符合条件的特定实体被调用。假设有一系列基于名为 HasTimestamp 的 mixin 的类:

import datetime

class HasTimestamp:
    timestamp = mapped_column(DateTime, default=datetime.datetime.now)

class SomeEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

class SomeOtherEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

上述类 SomeEntitySomeOtherEntity 将分别具有一个默认为当前日期和时间的列 timestamp。可以使用事件拦截从 HasTimestamp 扩展的所有对象,并在一个月前之内的日期上过滤它们的 timestamp 列:

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        one_month_ago = datetime.datetime.today() - datetime.timedelta(months=1)

        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(
                HasTimestamp,
                lambda cls: cls.timestamp >= one_month_ago,
                include_aliases=True,
            )
        )

警告

在调用with_loader_criteria()时使用 lambda 只会每个唯一类调用一次。在此 lambda 内部不应调用自定义函数。有关“lambda SQL”功能的概述,请参阅使用 Lambda 为语句生成带来显著速度提升,这仅适用于高级用法。

另请参阅

ORM 查询事件 - 包括上述with_loader_criteria()示例的工作示例。### 重新执行语句

深度炼金术

重新执行功能涉及稍微复杂的递归序列,并旨在解决能够将 SQL 语句的执行重新路由到各种非 SQL 上下文的相当困难的问题。下面链接的“狗窝缓存”和“水平分片”这两个示例应该作为指导,指出何时适合使用这个相当高级的功能。

ORMExecuteState能够控制给定语句的执行;这包括不执行语句的能力,允许从缓存中检索到的预构建结果集返回,以及多次以不同状态调用相同语句的能力,例如针对多个数据库连接调用它,然后在内存中合并结果。这两种高级模式在 SQLAlchemy 的示例套件中有详细展示。

当在SessionEvents.do_orm_execute()事件钩子内部时,可以使用ORMExecuteState.invoke_statement()方法来使用新的嵌套调用Session.execute()来调用语句,这将预先中断当前正在进行的执行的后续处理,而是返回内部执行返回的Result。在此过程中为SessionEvents.do_orm_execute()钩子调用的事件处理程序也将在此嵌套调用中被跳过。

ORMExecuteState.invoke_statement()方法返回一个Result对象;该对象具有将其“冻结”为可缓存格式并“解冻”为新的Result对象的能力,以及将其数据与其他Result对象的数据合并的能力。

例如,使用SessionEvents.do_orm_execute()来实现缓存:

from sqlalchemy.orm import loading

cache = {}

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if "my_cache_key" in orm_execute_state.execution_options:
        cache_key = orm_execute_state.execution_options["my_cache_key"]

        if cache_key in cache:
            frozen_result = cache[cache_key]
        else:
            frozen_result = orm_execute_state.invoke_statement().freeze()
            cache[cache_key] = frozen_result

        return loading.merge_frozen_result(
            orm_execute_state.session,
            orm_execute_state.statement,
            frozen_result,
            load=False,
        )

有了上述钩子,使用缓存的示例如下:

stmt = (
    select(User).where(User.name == "sandy").execution_options(my_cache_key="key_sandy")
)

result = session.execute(stmt)

以上,在Select.execution_options()中传递了一个自定义执行选项,以建立一个“缓存键”,然后会被SessionEvents.do_orm_execute()钩子拦截。这个缓存键然后会与可能存在于缓存中的FrozenResult对象匹配,如果存在,则会重新使用该对象。该示例利用了Result.freeze()方法来“冻结”一个Result对象,其中将包含 ORM 结果,以便将其存储在缓存中并多次使用。为了从“冻结”结果中返回一个实时结果,使用merge_frozen_result()函数将结果对象中的“冻结”数据合并到当前会话中。

上述示例在 Dogpile Caching 中作为一个完整示例实现。

ORMExecuteState.invoke_statement() 方法也可以被多次调用,传递不同的信息给 ORMExecuteState.invoke_statement.bind_arguments 参数,以便 Session 每次都使用不同的 Engine 对象。每次都会返回一个不同的 Result 对象;这些结果可以使用 Result.merge() 方法合并在一起。这是 水平分片 扩展所使用的技术;请查看源代码以熟悉。

另请参阅

Dogpile Caching

水平分片

基本查询拦截

SessionEvents.do_orm_execute() 首先适用于任何类型的查询拦截,包括由 Query 以 1.x 样式 发出的查询,以及当启用 ORM 的 2.0 样式 select()update()delete() 构造传递给 Session.execute() 时。 ORMExecuteState 构造提供了访问器,允许对语句、参数和选项进行修改:

Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if orm_execute_state.is_select:
        # add populate_existing for all SELECT statements

        orm_execute_state.update_execution_options(populate_existing=True)

        # check if the SELECT is against a certain entity and add an
        # ORDER BY if so
        col_descriptions = orm_execute_state.statement.column_descriptions

        if col_descriptions[0]["entity"] is MyEntity:
            orm_execute_state.statement = statement.order_by(MyEntity.name)

上述示例说明了对 SELECT 语句的一些简单修改。在此级别上,SessionEvents.do_orm_execute()事件挂钩旨在替换先前使用的QueryEvents.before_compile()事件,该事件对各种加载程序未始终触发;另外,QueryEvents.before_compile()仅适用于 1.x 样式与Query一起使用,而不适用于 2.0 样式使用Session.execute()

添加全局 WHERE / ON 条件

最常请求的查询扩展功能之一是能够向所有查询中的实体添加 WHERE 条件的能力。这可以通过使用with_loader_criteria()查询选项来实现,该选项可以单独使用,或者最好在SessionEvents.do_orm_execute()事件中使用:

from sqlalchemy.orm import with_loader_criteria

Session = sessionmaker(engine)

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(MyEntity.public == True)
        )

在上述示例中,一个选项被添加到所有 SELECT 语句中,该选项将限制所有针对MyEntity的查询以在public == True上进行过滤。这些条件将应用于立即查询范围内该类的所有加载。with_loader_criteria()选项默认情况下也会自动传播到关系加载程序,这将应用于后续的关系加载,包括惰性加载、selectinloads 等。

对于一系列具有一些共同列结构的类,如果使用声明性混合组合类,那么混合类本身可以与with_loader_criteria()选项一起使用,方法是使用 Python lambda。Python lambda 将在与条件匹配的特定实体的查询编译时间调用。假设有一系列基于名为HasTimestamp的混合类的类:

import datetime

class HasTimestamp:
    timestamp = mapped_column(DateTime, default=datetime.datetime.now)

class SomeEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

class SomeOtherEntity(HasTimestamp, Base):
    __tablename__ = "some_entity"
    id = mapped_column(Integer, primary_key=True)

上述类SomeEntitySomeOtherEntity将各自具有一个列timestamp,默认值为当前日期和时间。可以使用事件拦截所有从HasTimestamp扩展的对象,并将它们的timestamp列过滤为一个月前的日期:

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if (
        orm_execute_state.is_select
        and not orm_execute_state.is_column_load
        and not orm_execute_state.is_relationship_load
    ):
        one_month_ago = datetime.datetime.today() - datetime.timedelta(months=1)

        orm_execute_state.statement = orm_execute_state.statement.options(
            with_loader_criteria(
                HasTimestamp,
                lambda cls: cls.timestamp >= one_month_ago,
                include_aliases=True,
            )
        )

警告

在调用 with_loader_criteria() 时,使用 lambda 内部的调用每个唯一类仅调用一次。自定义函数不应在此 lambda 内部调用。请参阅 使用 Lambda 来为语句生成带来显著的速度提升 以获得“lambda SQL”功能的概述,该功能仅供高级使用。

另请参阅

ORM 查询事件 - 包括上述 with_loader_criteria() 配方的工作示例。

重新执行语句

深度炼金术

语句重新执行功能涉及稍微复杂的递归序列,并且旨在解决将 SQL 语句的执行重新路由到各种非 SQL 上下文的相当困难的问题。下面链接的“狗窝缓存”和“水平分片”两个示例应该用作指导,以确定何时使用此相当高级的功能。

ORMExecuteState 能够控制给定语句的执行;这包括不执行该语句的能力,允许从缓存中检索到的预构造结果集被返回,以及多次以不同状态调用相同语句的能力,例如对多个数据库连接执行它,然后在内存中合并结果。这两种高级模式都在下面详细介绍了 SQLAlchemy 的示例套件中进行了演示。

SessionEvents.do_orm_execute() 事件钩子内部时,可以使用 ORMExecuteState.invoke_statement() 方法来使用新的嵌套调用 Session.execute() 来调用语句,这将预先阻止当前正在进行的执行的后续处理,并返回内部执行的 Result。在此过程中对 SessionEvents.do_orm_execute() 钩子所调用的事件处理程序也将在此嵌套调用中被跳过。

ORMExecuteState.invoke_statement()方法返回一个Result对象;此对象具有将其“冻结”为可缓存格式并“解冻”为新的Result对象的能力,以及将其数据与其他Result对象的数据合并的能力。

例如,使用SessionEvents.do_orm_execute()实现缓存:

from sqlalchemy.orm import loading

cache = {}

@event.listens_for(Session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
    if "my_cache_key" in orm_execute_state.execution_options:
        cache_key = orm_execute_state.execution_options["my_cache_key"]

        if cache_key in cache:
            frozen_result = cache[cache_key]
        else:
            frozen_result = orm_execute_state.invoke_statement().freeze()
            cache[cache_key] = frozen_result

        return loading.merge_frozen_result(
            orm_execute_state.session,
            orm_execute_state.statement,
            frozen_result,
            load=False,
        )

有了上述钩子,使用缓存的示例如下所示:

stmt = (
    select(User).where(User.name == "sandy").execution_options(my_cache_key="key_sandy")
)

result = session.execute(stmt)

上面,在Select.execution_options()中传递了自定义执行选项,以建立一个“缓存键”,然后会被SessionEvents.do_orm_execute()钩子拦截。然后将该缓存键与可能存在于缓存中的FrozenResult对象进行匹配,如果存在,则重新使用该对象。该方案利用了Result.freeze()方法来“冻结”一个Result对象,其中包含上面的 ORM 结果,以便将其存储在缓存中并多次使用。为了从“冻结”的结果中返回实时结果,使用了merge_frozen_result()函数将结果对象中的“冻结”数据合并到当前会话中。

上述示例已作为一个完整示例在 Dogpile Caching 中实现。

ORMExecuteState.invoke_statement() 方法也可能被多次调用,传递不同的信息给 ORMExecuteState.invoke_statement.bind_arguments 参数,以便 Session 每次使用不同的 Engine 对象。这将每次返回一个不同的 Result 对象;这些结果可以使用 Result.merge() 方法合并在一起。这是水平分片扩展所采用的技术;请参阅源代码以熟悉。

另请参阅

Dogpile 缓存

水平分片

持久性事件

最广泛使用的系列事件可能是“持久性”事件,它们对应于刷新过程。 刷新是关于对对象的待定更改的所有决定都是在这里做出的,然后以 INSERT、UPDATE 和 DELETE 语句的形式发出到数据库。

before_flush()

SessionEvents.before_flush() 钩子是应用程序希望在提交时确保对数据库进行额外持久性更改时最常用的事件。使用 SessionEvents.before_flush() 来在对象上操作以验证它们的状态,以及在它们持久化之前组合额外的对象和引用。在此事件中,操纵会话状态是安全的,也就是说,新对象可以附加到它,对象可以被删除,并且可以自由更改对象上的单个属性,并且这些更改将在事件挂钩完成时被纳入到刷新过程中。

典型的SessionEvents.before_flush()挂钩将负责扫描集合Session.newSession.dirtySession.deleted,以查找将要发生变化的对象。

对于SessionEvents.before_flush()的示例,请参阅使用历史表进行版本控制和使用时间行进行版本控制等示例。

after_flush()

在 SQL 被发出进行刷新过程后,但是在被刷新的对象的状态被改变之前,会调用SessionEvents.after_flush()挂钩。也就是说,你仍然可以检查Session.newSession.dirtySession.deleted这些集合,看看刚刚刷新了什么,你也可以使用像AttributeState提供的历史跟踪功能来查看刚刚持久化了什么更改。在SessionEvents.after_flush()事件中,可以根据观察到的变化向数据库发出其他 SQL。

after_flush_postexec()

SessionEvents.after_flush_postexec()SessionEvents.after_flush() 之后不久被调用,但在考虑了刚刚发生的刷新后对象状态被修改的情况下调用。Session.newSession.dirtySession.deleted 集合通常在这里是完全空的。使用 SessionEvents.after_flush_postexec() 来检查已完成对象的标识映射并可能发出额外的 SQL。在这个钩子中,有能力对对象进行新的更改,这意味着 Session 将再次进入“dirty”状态;如果在此钩子中检测到新的更改,则会导致 Session 的机制再次刷新一次,如果在 Session.commit() 的上下文中调用刷新并检测到新的更改,则否则,挂起的更改将作为下一个正常刷新的一部分捆绑在一起。当钩子在 Session.commit() 中检测到新的更改时,计数器确保在每次调用时都添加新的状态时不会无限循环,以防止无休止的循环在这方面在经过 100 次迭代后停止。

Mapper 级别的刷新事件

除了刷新级别的钩子外,还有一组更细粒度的钩子,它们是基于每个对象的并且根据刷新过程中的 INSERT、UPDATE 或 DELETE 而分开的。这些是映射器持久性钩子,它们也非常受欢迎,但是需要更加谨慎地对待这些事件,因为它们在已经进行中的刷新过程的上下文中进行;在这里进行许多操作是不安全的。

事件包括:

  • MapperEvents.before_insert()

  • MapperEvents.after_insert()

  • MapperEvents.before_update()

  • MapperEvents.after_update()

  • MapperEvents.before_delete()

  • MapperEvents.after_delete()

注意

重要的是要注意,这些事件仅适用于会话刷新操作,而不适用于在 ORM-Enabled INSERT、UPDATE 和 DELETE 语句中描述的 ORM 级别的 INSERT/UPDATE/DELETE 功能。要拦截 ORM 级别的 DML,请使用SessionEvents.do_orm_execute()事件。

每个事件都会传递Mapper、映射对象本身以及正在用于发出 INSERT、UPDATE 或 DELETE 语句的Connection。这些事件的吸引力是显而易见的,因为如果一个应用程序想要将某些活动与特定类型的对象被插入时联系起来,那么钩子就非常具体;不像SessionEvents.before_flush()事件那样,不需要搜索像Session.new这样的集合以找到目标。然而,在调用这些事件时,表示将要发出的每个单独的 INSERT、UPDATE、DELETE 语句的 flush 计划已经已经决定,并且在此阶段不能做出任何更改。因此,对给定对象的唯一可能的更改是对对象行本地的属性进行。对对象或其他对象的任何其他更改将影响Session的状态,这将导致其无法正常工作。

不支持这些映射器级别持久性事件中的操作包括:

  • Session.add()

  • Session.delete()

  • 映射集合的附加、添加、删除、丢弃等操作。

  • 映射关系属性设置/删除事件,即someobject.related = someotherobject

传递Connection的原因是鼓励在此处执行简单的 SQL 操作,直接在Connection上,例如增加计数器或在日志表中插入额外行。

也有许多不需要在刷新事件中处理的每个对象操作。最常见的替代方法是简单地在对象的__init__()方法中与对象一起建立附加状态,例如创建与新对象关联的其他对象。使用如简单验证器中所述的验证器是另一种方法;这些函数可以拦截对属性的更改,并在响应属性更改时在目标对象上建立额外的状态更改。使用这两种方法,对象在到达刷新步骤之前处于正确的状态。

before_flush()

SessionEvents.before_flush() 钩子是应用程序希望确保在提交刷新时进行额外持久化更改时最常用的事件。使用SessionEvents.before_flush() 来操作对象以验证其状态,并在持久化之前组成额外的对象和引用。在此事件中,操作会话的状态是安全的,即,新对象可以附加到其中,对象可以被删除,并且可以自由更改对象上的单个属性,并且这些更改将在事件钩子完成时被引入到刷新过程中。

典型的SessionEvents.before_flush() 钩子将负责扫描集合Session.newSession.dirtySession.deleted,以查找将发生事情的对象。

有关SessionEvents.before_flush()的示例,请参见带有历史表的版本控制和使用时间行进行版本控制等示例。

after_flush()

SessionEvents.after_flush() 钩子在 flush 过程中的 SQL 已经被发出,但是在被刷新的对象状态被改变之前被调用。也就是说,您仍然可以检查 Session.newSession.dirtySession.deleted 集合,看看刚刚被刷新了什么,您还可以使用像 AttributeState 提供的历史跟踪功能来查看刚刚持久化的更改。在 SessionEvents.after_flush() 事件中,根据观察到的更改,可以向数据库发出其他 SQL。

after_flush_postexec()

SessionEvents.after_flush_postexec()SessionEvents.after_flush() 之后不久调用,但是在对象的状态已经修改以反映刚刚发生的刷新之后调用。这里 Session.newSession.dirtySession.deleted 集合通常完全为空。使用 SessionEvents.after_flush_postexec() 来检查最终化对象的标识映射,并可能发出其他 SQL。在这个钩子中,有能力对对象进行新的更改,这意味着 Session 将再次进入“dirty”状态;如果在 Session.commit() 的上下文中调用此钩子时检测到新的更改,那么Session 的机制会导致它再次刷新;否则,待定的更改将作为下一个正常刷新的一部分捆绑在一起。当钩子在 Session.commit() 中检测到新的更改时,计数器会在此方面的无限循环在 100 次迭代后停止,在这种情况下,如果 SessionEvents.after_flush_postexec() 钩子每次调用时都持续添加新的要刷新的状态,就会停止。

映射器级别的刷新事件

除了刷新级别的钩子外,还有一套更精细的钩子,因为它们是基于每个对象调用的,并根据刷新过程中的 INSERT、UPDATE 或 DELETE 进行分组。这些是映射器持久性钩子,它们也非常受欢迎,但是这些事件需要更谨慎地处理,因为它们在已经进行的刷新过程的上下文中进行;许多操作在这里进行不安全。

事件包括:

  • MapperEvents.before_insert()

  • MapperEvents.after_insert()

  • MapperEvents.before_update()

  • MapperEvents.after_update()

  • MapperEvents.before_delete()

  • MapperEvents.after_delete()

注意

重要的是要注意,这些事件适用于会话刷新操作,而不是描述的 ORM 级别的 INSERT/UPDATE/DELETE 功能 ORM-Enabled INSERT, UPDATE, and DELETE statements。要拦截 ORM 级别的 DML,请使用SessionEvents.do_orm_execute()事件。

每个事件都会传递Mapper、映射对象本身和用于发出 INSERT、UPDATE 或 DELETE 语句的Connection。这些事件的吸引力是显而易见的,因为如果应用程序想要将某些活动与在 INSERT 时持久化特定类型的对象绑定起来,这个钩子就非常具体;与SessionEvents.before_flush()事件不同,不需要搜索像Session.new这样的集合来找到目标。然而,在调用这些事件时,表示要发出的每个单独的 INSERT、UPDATE、DELETE 语句的刷新计划已经已经确定,在此阶段无法进行任何更改。因此,甚至可能对给定对象进行的唯一更改是对对象行的本地属性。对于对象或其他对象的任何其他更改都将影响到Session的状态,这将导致其无法正常工作。

在这些映射器级别的持久性事件中不支持的操作包括:

  • Session.add()

  • Session.delete()

  • 映射的集合追加、添加、移除、删除、丢弃等操作。

  • 映射的关系属性设置/删除事件,即someobject.related = someotherobject

传递Connection的原因是鼓励在这里进行简单的 SQL 操作,直接在Connection上进行,比如增加计数器或在日志表中插入额外行。

还有许多不需要在刷新事件中处理的每个对象操作。最常见的替代方法是在对象的__init__()方法中简单地建立额外状态,比如创建要与新对象关联的其他对象。另一种方法是使用简单验证器中描述的验证器;这些函数可以拦截属性的更改,并在响应属性更改时在目标对象上建立额外的状态更改。使用这两种方法,对象在进入刷新步骤之前就处于正确状态。

对象生命周期事件

事件的另一个用例是跟踪对象的生命周期。这指的是首次介绍的状态,即快速介绍对象状态。

所有上述状态都可以通过事件完全跟踪。每个事件代表一个不同的状态转换,意味着起始状态和目标状态都是被跟踪的一部分。除了初始瞬态事件之外,所有事件都是以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)

瞬态

当所有映射对象首次构建时,它们都是瞬态的。在此状态下,对象单独存在,并且不与任何Session相关联。对于这种初始状态,没有特定的“转换”事件,因为没有Session,但是如果想要拦截任何瞬态对象被创建时,InstanceEvents.init() 方法可能是最好的事件。此事件适用于特定的类或超类。例如,要拦截特定声明基类的所有新对象:

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import event

class Base(DeclarativeBase):
    pass

@event.listens_for(Base, "init", propagate=True)
def intercept_init(instance, args, kwargs):
    print("new transient: %s" % instance)

瞬态到挂起

当瞬态对象首次通过Session.add()Session.add_all()方法与Session关联时,瞬态对象变为挂起。对象也可能作为显式添加的引用对象的“级联”的结果之一而成为Session的一部分。可以使用SessionEvents.transient_to_pending()事件检测瞬态到挂起的转换:

@event.listens_for(sessionmaker, "transient_to_pending")
def intercept_transient_to_pending(session, object_):
    print("transient to pending: %s" % object_)

挂起到持久

当刷新继续并且针对实例进行 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_)

挂起到瞬态

如果在挂起对象刷新之前调用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 语句才会被发出。在刷新之后,目标对象将处于“deleted”状态。

在“deleted”状态下,对象与 Session 仅有轻微关联。它不在标识映射中,也不在指示它何时待删除的 Session.deleted 集合中。

从“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_)

删除到分离

当会话的事务提交后,删除的对象会变成分离。在调用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_)

注意

当对象处于删除状态时,可通过inspect(object).deleted访问InstanceState.deleted属性,返回 True。然而,当对象被分离时,InstanceState.deleted将再次返回 False。要检测对象是否已被删除,无论它是否分离,都可以使用InstanceState.was_deleted访问器。

持久到分离

当对象使用Session.expunge()Session.expunge_all()Session.close()方法与Session解除关联时,持久对象将变为分离。

注意

如果应用程序解除引用并由于垃圾回收而丢弃了拥有的Session,则对象也可能隐式分离。在这种情况下,不会触发任何事件

使用SessionEvents.persistent_to_detached()事件跟踪对象从持久到分离的移动:

@event.listens_for(sessionmaker, "persistent_to_detached")
def intercept_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 intercept_detached_to_persistent(session, object_):
    print("object became persistent again: %s" % object_)

删除到持久

当用于 DELETE 的事务使用Session.rollback()方法回滚时,已删除对象可以恢复为持久状态。使用SessionEvents.deleted_to_persistent()事件跟踪已删除对象移回持久状态:

@event.listens_for(sessionmaker, "deleted_to_persistent")
def intercept_deleted_to_persistent(session, object_):
    print("deleted to persistent: %s" % object_)

暂时

所有映射对象在首次构造时都作为暂时状态开始。在这种状态下,对象单独存在,并且不与任何Session相关联。对于这种初始状态,没有特定的“转换”事件,因为没有Session,但是如果想要拦截任何暂时对象被创建的情况,InstanceEvents.init()方法可能是最好的事件。此事件适用于特定类或超类。例如,要拦截特定声明基类的所有新对象:

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import event

class Base(DeclarativeBase):
    pass

@event.listens_for(Base, "init", propagate=True)
def intercept_init(instance, args, kwargs):
    print("new transient: %s" % instance)

暂时到待定

当暂时对象首次通过Session.add()Session.add_all()方法与Session相关联时,暂时对象变为待定状态。对象也可能作为引用对象的“级联”结果成为Session的一部分,该引用对象已明确添加。可以使用SessionEvents.transient_to_pending()事件检测从暂时到待定的转换:

@event.listens_for(sessionmaker, "transient_to_pending")
def intercept_transient_to_pending(session, object_):
    print("transient to pending: %s" % object_)

待定到持久

待定对象在执行冲洗并为该实例执行插入语句时变为持久状态。对象现在具有标识键。使用SessionEvents.pending_to_persistent()事件跟踪待定对象到持久状态的转换:

@event.listens_for(sessionmaker, "pending_to_persistent")
def intercept_pending_to_persistent(session, object_):
    print("pending to persistent: %s" % object_)

待定到暂时

如果在待定对象被刷新之前调用了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中,当它们从数据库中加载时。跟踪这种状态转换与跟踪对象的加载是同义的,并且与使用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_)

持久化到已删除

在刷新过程中,如果标记为删除的对象从数据库中被删除,则持久化对象进入已删除状态。请注意,这调用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_)

删除到分离

当会话的事务提交后,被删除的对象会变成分离状态。在调用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_)

注意

当对象处于删除状态时,可以通过inspect(object).deleted访问的InstanceState.deleted属性返回 True。但是当对象分离时,InstanceState.deleted将再次返回 False。要检测对象是否已被删除,无论它是否分离,请使用InstanceState.was_deleted访问器。

持久到分离

当对象与Session取消关联时,通过Session.expunge()Session.expunge_all()Session.close()方法,持久对象会变成分离状态。

注意

如果由于垃圾回收应用程序取消引用并丢弃了拥有对象的Session,则对象也可能隐式分离。在这种情况下,不会发出任何事件

使用SessionEvents.persistent_to_detached()事件跟踪对象从持久化到分离的移动:

@event.listens_for(sessionmaker, "persistent_to_detached")
def intercept_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 intercept_detached_to_persistent(session, object_):
    print("object became persistent again: %s" % object_)

删除到持久化

当以 DELETE 方式删除对象的事务被使用Session.rollback()方法回滚时,删除对象可以恢复到持久化状态。跟踪已删除对象从删除状态返回持久化状态,请使用SessionEvents.deleted_to_persistent()事件:

@event.listens_for(sessionmaker, "deleted_to_persistent")
def intercept_deleted_to_persistent(session, object_):
    print("deleted to persistent: %s" % object_)

事务事件

事务事件允许应用程序在Session级别发生事务边界以及SessionConnection对象上更改事务状态时得到通知。

  • SessionEvents.after_transaction_create(), SessionEvents.after_transaction_end() - 这些事件跟踪Session的逻辑事务范围,与个别数据库连接无关。这些事件旨在帮助集成诸如zope.sqlalchemy之类的事务跟踪系统。当应用程序需要将某些外部范围与Session的事务范围对齐时,请使用这些事件。这些钩子反映了Session的“嵌套”事务行为,因为它们不仅跟踪逻辑“子事务”,还跟踪“嵌套”(例如 SAVEPOINT)事务。

  • SessionEvents.before_commit(), SessionEvents.after_commit(), SessionEvents.after_begin(), SessionEvents.after_rollback(), SessionEvents.after_soft_rollback() - 这些事件允许从数据库连接的角度跟踪事务事件。特别是SessionEvents.after_begin() 是一个每个连接的事件;一个维护多个连接的 Session 将在当前事务中使用这些连接时为每个连接单独发出此事件。然后回滚和提交事件是指 DBAPI 连接本身何时直接收到回滚或提交指令。

属性更改事件

属性更改事件允许拦截对象上特定属性被修改的情况。这些事件包括AttributeEvents.set(), AttributeEvents.append(), 和 AttributeEvents.remove()。这些事件非常有用,特别是用于每个对象的验证操作;然而,通常更方便使用“验证器”钩子,该钩子在幕后使用这些钩子;请参阅简单验证器 了解背景信息。属性事件也在反向引用的机制后面。一个示例说明了属性事件的使用在属性检测。

Session API

原文:docs.sqlalchemy.org/en/20/orm/session_api.html

Session 和 sessionmaker()

对象名称 描述
ORMExecuteState 表示对Session.execute()方法的调用,作为传递给SessionEvents.do_orm_execute()事件钩子的参数。
Session 管理 ORM 映射对象的持久化操作。
sessionmaker 可配置的Session工厂。
SessionTransaction 一个Session级别的事务。
SessionTransactionOrigin 表示SessionTransaction的来源。
class sqlalchemy.orm.sessionmaker

可配置的Session工厂。

sessionmaker工厂在调用时生成新的Session对象,在此处建立的配置参数的基础上创建它们。

例如:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# an Engine, which the Session will use for connection
# resources
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')

Session = sessionmaker(engine)

with Session() as session:
    session.add(some_object)
    session.add(some_other_object)
    session.commit()

上下文管理器的使用是可选的;否则,通过Session.close()方法可以显式关闭返回的Session对象。使用try:/finally:块是可选的,但是会确保即使存在数据库错误,关闭也会发生:

session = Session()
try:
    session.add(some_object)
    session.add(some_other_object)
    session.commit()
finally:
    session.close()

sessionmaker充当Engine充当Connection对象的工厂的工厂。以这种方式,它还包括一个sessionmaker.begin()方法,提供一个上下文管理器,该管理器既开始又提交事务,完成后关闭Session,如果出现任何错误,则回滚事务:

Session = sessionmaker(engine)

with Session.begin() as session:
    session.add(some_object)
    session.add(some_other_object)
# commits transaction, closes session

新版本 1.4 中新增。

当调用sessionmaker来构造一个Session时,也可以传递关键字参数给方法;这些参数将覆盖全局配置的参数。下面我们使用一个绑定到某个Enginesessionmaker来生成一个Session,而该Session则绑定到从该引擎获取的特定Connection上:

Session = sessionmaker(engine)

# bind an individual session to a connection

with engine.connect() as connection:
    with Session(bind=connection) as session:
        # work with session

该类还包括一个方法sessionmaker.configure(),用于指定工厂的其他关键字参数,这些参数将对生成的后续Session对象生效。通常用于在首次使用之前将一个或多个Engine对象与现有的sessionmaker工厂关联起来:

# application starts, sessionmaker does not have
# an engine bound yet
Session = sessionmaker()

# ... later, when an engine URL is read from a configuration
# file or other events allow the engine to be created
engine = create_engine('sqlite:///foo.db')
Session.configure(bind=engine)

sess = Session()
# work with session

另请参阅

打开和关闭会话 - 关于使用sessionmaker创建会话的介绍性文本。

成员

call(), init(), begin(), close_all(), configure(), identity_key(), object_session()

类签名

sqlalchemy.orm.sessionmakersqlalchemy.orm.session._SessionClassMethods, typing.Generic

method __call__(**local_kw: Any) → _S

使用在这个sessionmaker中建立的配置生成一个新的Session对象。

在 Python 中,当对象“被调用”时,会调用__call__方法,其方式与函数相同:

Session = sessionmaker(some_engine)
session = Session()  # invokes sessionmaker.__call__()
method __init__(bind: Optional[_SessionBind] = None, *, class_: Type[_S] = <class 'sqlalchemy.orm.session.Session'>, autoflush: bool = True, expire_on_commit: bool = True, info: Optional[_InfoType] = None, **kw: Any)

构造一个新的sessionmaker

这里的所有参数,除了class_之外,都与Session直接接受的参数相对应。有关参数的更多详细信息,请参阅Session.__init__()文档字符串。

参数:

  • bind – 一个Engine或其他Connectable,新创建的Session对象将与之关联。

  • class_ – 用于创建新的Session对象的类。默认为Session

  • autoflush

    用于新创建的Session对象的自动刷新设置。

    另请参阅

    刷新 - 关于自动刷新的额外背景信息

  • expire_on_commit=True – 用于新创建的Session对象的Session.expire_on_commit设置。

  • info – 可选信息字典,将通过Session.info可用。请注意,当指定info参数进行特定Session构造操作时,此字典将被更新,而不是替换。

  • **kw – 所有其他关键字参数都传递给新创建的Session对象的构造函数。

method begin() → AbstractContextManager[_S]

生成一个上下文管理器,既提供一个新的Session,又提供一个提交的事务。

例如:

Session = sessionmaker(some_engine)

with Session.begin() as session:
    session.add(some_object)

# commits transaction, closes session

版本 1.4 中的新功能。

classmethod close_all() → None

继承自 sqlalchemy.orm.session._SessionClassMethods.close_all 方法的 sqlalchemy.orm.session._SessionClassMethods

关闭内存中的所有会话。

自版本 1.3 起已弃用:Session.close_all()方法已弃用,并将在将来的版本中删除。请参考close_all_sessions()

method configure(**new_kw: Any) → None

(重新)配置此 sessionmaker 的参数。

例如:

Session = sessionmaker()

Session.configure(bind=create_engine('sqlite://'))
classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

继承自 sqlalchemy.orm.session._SessionClassMethods.identity_key 方法的 sqlalchemy.orm.session._SessionClassMethods

返回一个标识键。

这是identity_key()的别名。

classmethod object_session(instance: object) → Session | None

继承自 sqlalchemy.orm.session._SessionClassMethods.object_session 方法的 sqlalchemy.orm.session._SessionClassMethods

返回一个对象所属的Session

这是object_session()的别名。

class sqlalchemy.orm.ORMExecuteState

表示对Session.execute()方法的调用,作为传递给SessionEvents.do_orm_execute()事件钩子的参数。

版本 1.4 中的新功能。

另请参阅

执行事件 - 如何使用SessionEvents.do_orm_execute()的顶级文档。

成员

init(), all_mappers, bind_arguments, bind_mapper, execution_options, invoke_statement(), is_column_load, is_delete, is_executemany, is_from_statement, is_insert, is_orm_statement, is_relationship_load, is_select, is_update, lazy_loaded_from, load_options, loader_strategy_path, local_execution_options, parameters, session, statement, update_delete_options, update_execution_options(), user_defined_options

类签名

sqlalchemy.orm.ORMExecuteState (sqlalchemy.util.langhelpers.MemoizedSlots)

method __init__(session: Session, statement: Executable, parameters: _CoreAnyExecuteParams | None, execution_options: _ExecuteOptions, bind_arguments: _BindArguments, compile_state_cls: Type[ORMCompileState] | None, events_todo: List[_InstanceLevelDispatch[Session]])

构造一个新的ORMExecuteState

此对象是在内部构造的。

attribute all_mappers

返回此语句顶层涉及的所有Mapper对象的序列。

“顶级”指的是那些在select()查询的结果集行中表示的Mapper对象,或者在update()delete()查询中,是 UPDATE 或 DELETE 的主体。

版本 1.4.0b2 中的新内容。

另见

ORMExecuteState.bind_mapper

attribute bind_arguments: _BindArguments

字典作为 Session.execute.bind_arguments 字典传递。

此字典可由扩展用于 Session 以传递将有助于确定一组数据库连接中的哪一个应该用于调用此语句的参数。

attribute bind_mapper

返回是主“绑定”映射器的 Mapper

对于调用 ORM 语句的 ORMExecuteState 对象,即 ORMExecuteState.is_orm_statement 属性为 True 的情况,此属性将返回被视为语句的“主”映射器。术语“绑定映射器”指的是 Session 对象可能“绑定”到多个映射类键入的多个 Engine 对象,并且“绑定映射器”确定将选择哪个 Engine 对象。

对于针对单个映射类调用的语句,ORMExecuteState.bind_mapper 旨在是获取此映射器的可靠方法。

版本 1.4.0b2 中的新功能。

另请参阅

ORMExecuteState.all_mappers

attribute execution_options: _ExecuteOptions

当前执行选项的完整字典。

这是语句级选项与本地传递的执行选项的合并。

另请参阅

ORMExecuteState.local_execution_options

Executable.execution_options()

ORM 执行选项

method invoke_statement(statement: Executable | None = None, params: _CoreAnyExecuteParams | None = None, execution_options: OrmExecuteOptionsParameter | None = None, bind_arguments: _BindArguments | None = None) → Result[Any]

执行由此 ORMExecuteState 表示的语句,而不重新调用已经进行过的事件。

此方法本质上执行当前语句的可重入执行,即当前调用 SessionEvents.do_orm_execute() 事件。这样做的用例是为了事件处理程序想要重写如何返回最终 Result 对象,比如从离线缓存检索结果或者将结果从多次执行中连接起来的方案。

当实际处理程序函数在 SessionEvents.do_orm_execute() 中返回 Result 对象,并且传播到调用 Session.execute() 方法的地方时,Session.execute() 方法的其余部分将被抢占,并且 Result 对象将立即返回给 Session.execute() 的调用者。

参数:

  • statement – 可选的语句,用于代替当前由 ORMExecuteState.statement 表示的语句。

  • params

    可选的参数字典或参数列表将合并到此 ORMExecuteState 的现有 ORMExecuteState.parameters 中。

    2.0 版更改:接受参数字典列表进行 executemany 执行。

  • execution_options – 可选的执行选项字典将合并到此 ORMExecuteState 的现有 ORMExecuteState.execution_options 中。

  • bind_arguments – 可选的 bind_arguments 字典将在此 ORMExecuteState 的当前 ORMExecuteState.bind_arguments 中合并。

返回:

一个带有 ORM 级结果的 Result 对象。

另见

重新执行语句 - 关于 ORMExecuteState.invoke_statement() 的适当用法的背景和示例。

attribute is_column_load

如果操作是刷新现有 ORM 对象上的基于列的属性,则返回 True。

在诸如 Session.refresh() 的操作期间发生,以及当由 defer() 推迟的属性正在加载时,或者由 Session.expire() 直接或通过提交操作而过期的属性正在加载时。

处理程序在进行此类操作时很可能不希望向查询添加任何选项,因为查询应该是直接的主键获取,不应该有任何额外的 WHERE 条件,并且实例旅行的加载器选项已经添加到查询中。

版本 1.4.0b2 中的新功能。

另请参阅

ORMExecuteState.is_relationship_load

attribute is_delete

如果这是一个 DELETE 操作,则返回 True。

2.0.30 版本中的更改:- 该属性对 Select.from_statement() 构造也是真的,该构造本身针对 Delete 构造,例如 select(Entity).from_statement(delete(..))

attribute is_executemany

如果参数是一个包含多个字典且字典数量大于一个的列表,则返回 True。

版本 2.0 中的新功能。

attribute is_from_statement

如果此操作是 Select.from_statement() 操作,则返回 True。

这与 ORMExecuteState.is_select 独立,因为 select().from_statement() 构造也可以与 INSERT/UPDATE/DELETE RETURNING 类型的语句一起使用。ORMExecuteState.is_select 仅在 Select.from_statement() 本身针对 Select 构造时设置。

版本 2.0.30 中的新功能。

attribute is_insert

如果这是一个 INSERT 操作,则返回 True。

在 2.0.30 版本中更改: - 该属性对Select.from_statement()构造也为 True,该构造本身针对Insert构造,例如select(Entity).from_statement(insert(..))

attribute is_orm_statement

如果操作是 ORM 语句,则返回 True。

这表示所调用的 select()、insert()、update()或 delete()包含 ORM 实体作为主体。对于没有 ORM 实体,而只引用Table元数据的语句,它被调用为核心 SQL 语句,并且不发生 ORM 级别的自动化。

attribute is_relationship_load

如果此加载正在代表关系加载对象,则返回 True。

这意味着,加载程序实际上是一个 LazyLoader、SelectInLoader、SubqueryLoader 或类似的加载程序,并且整个发出的 SELECT 语句都是代表关系加载的。

处理程序很可能不希望在发生此类操作时向查询添加任何选项,因为加载程序选项已经能够传播到关系加载程序,并且应已存在。

另请参阅

ORMExecuteState.is_column_load

attribute is_select

如果这是一个 SELECT 操作,则返回 True。

在 2.0.30 版本中更改: - 该属性对Select.from_statement()构造也为 True,该构造本身针对Select构造,例如select(Entity).from_statement(select(..))

attribute is_update

如果这是一个 UPDATE 操作,则返回 True。

在 2.0.30 版本中更改: - 该属性对Select.from_statement()构造也为 True,该构造本身针对Update构造,例如select(Entity).from_statement(update(..))

attribute lazy_loaded_from

正在使用此语句执行进行延迟加载操作的InstanceState

此属性的主要理由是支持水平分片扩展,在此扩展创建的特定查询执行时间钩子中可用。为此,该属性仅打算在查询执行时间具有意义,而且重要的是不是在此之前的任何时间,包括查询编译时间。

attribute load_options

返回将用于此执行的load_options

attribute loader_strategy_path

返回当前加载路径的PathRegistry

此对象表示查询中关系的“路径”,当加载特定对象或集合时。

attribute local_execution_options: _ExecuteOptions

Session.execute() 方法传递的执行选项的字典视图。

这不包括与被调用语句相关的选项。

另请参阅

ORMExecuteState.execution_options

attribute parameters: _CoreAnyExecuteParams | None

传递给 Session.execute() 方法的参数字典。

attribute session: Session

正在使用的 Session

attribute statement: Executable

被调用的 SQL 语句。

对于像从 Query 检索到的 ORM 选择,这是从 ORM 查询生成的 select 的一个实例。

attribute update_delete_options

返回将用于此执行的 update_delete_options。

method update_execution_options(**opts: Any) → None

使用新值更新本地执行选项。

attribute user_defined_options

与被调用语句关联的 UserDefinedOptions 序列。

class sqlalchemy.orm.Session

管理 ORM 映射对象的持久化操作。

Session 不适用于并发线程。有关详情,请参阅会话是否线程安全? AsyncSession 是否安全可在并发任务中共享?。

关于 Session 的使用范例请参见使用 Session。

成员

init(), add(), add_all(), begin(), begin_nested(), bind_mapper(), bind_table(), bulk_insert_mappings(), bulk_save_objects(), bulk_update_mappings(), close(), close_all(), commit(), connection(), delete(), deleted, dirty, enable_relationship_loading(), execute(), expire(), expire_all(), expunge(), expunge_all(), flush(), get(), get_bind(), get_nested_transaction(), get_one(), get_transaction(), identity_key(), identity_map, in_nested_transaction(), in_transaction(), info, invalidate(), is_active, is_modified(), merge(), new, no_autoflush, object_session(), prepare(), query(), refresh(), reset(), rollback(), scalar(), scalars()

类签名

sqlalchemy.orm.Session (sqlalchemy.orm.session._SessionClassMethods, sqlalchemy.event.registry.EventTarget)

method __init__(bind: _SessionBind | None = None, *, autoflush: bool = True, future: Literal[True] = True, expire_on_commit: bool = True, autobegin: bool = True, twophase: bool = False, binds: Dict[_SessionBindKey, _SessionBind] | None = None, enable_baked_queries: bool = True, info: _InfoType | None = None, query_cls: Type[Query[Any]] | None = None, autocommit: Literal[False] = False, join_transaction_mode: JoinTransactionMode = 'conditional_savepoint', close_resets_only: bool | _NoArg = _NoArg.NO_ARG)

构建一个新的 Session

还请参阅 sessionmaker 函数,该函数用于生成具有给定参数集的产生 Session 的可调用对象。

参数:

  • autoflush

    当为True时,所有查询操作将在继续之前对此Session发出一个Session.flush()调用。这是一个方便的功能,使得不需要重复调用Session.flush()以便数据库查询检索结果。

    另请参阅

    刷新 - 自动刷新的额外背景

  • autobegin

    当请求由操作请求数据库访问时,自动启动事务(即相当于调用Session.begin())。默认为True。将其设置为False以防止Session在构造后隐式开始事务,以及在调用任何Session.rollback()Session.commit()Session.close()方法后隐式开始事务。

    2.0 版中的新功能。

    另请参阅

    禁用自动启动以防止隐式事务

  • bind – 此Session应绑定到的可选EngineConnection。当指定时,此会话执行的所有 SQL 操作都将通过此连接执行。

  • binds

    一个字典,可以指定任意数量的EngineConnection对象作为每个实体连接的源。字典的键由任何一系列映射类、任意的用作映射类基础的 Python 类、Table对象和Mapper对象组成。然后字典的值是Engine或较少常见的Connection对象的实例。针对特定映射类进行的操作将查询此字典,以确定用于特定 SQL 操作的最接近匹配实体为何。解析的完整启发式方法在Session.get_bind()中描述。用法如下:

    Session = sessionmaker(binds={
        SomeMappedClass: create_engine('postgresql+psycopg2://engine1'),
        SomeDeclarativeBase: create_engine('postgresql+psycopg2://engine2'),
        some_mapper: create_engine('postgresql+psycopg2://engine3'),
        some_table: create_engine('postgresql+psycopg2://engine4'),
        })
    

    另请参阅

    分区策略(例如每个会话的多个数据库后端)

    Session.bind_mapper()

    Session.bind_table()

    Session.get_bind()

  • class_ – 指定除了 sqlalchemy.orm.session.Session 之外的另一个类,该类应该由返回的类使用。 这是唯一一个本地于 sessionmaker 函数的参数,并且不直接发送到 Session 的构造函数。

  • enable_baked_queries

    经典; 默认为 True。 由 sqlalchemy.ext.baked 扩展消耗的一个参数,用于确定是否应该缓存“烘焙查询”,正如该扩展的正常操作一样。 当设置为 False 时,该特定扩展所使用的缓存被禁用。

    从版本 1.4 开始更改: sqlalchemy.ext.baked 扩展是遗留的,不被 SQLAlchemy 的任何内部使用。 因此,该标志仅影响在其自己的代码中明确使用此扩展的应用程序。

  • expire_on_commit

    默认为 True。 当为 True 时,每次 commit() 后所有实例都将完全过期,以便在完成事务后的所有属性/对象访问从最新的数据库状态加载。

    另请参阅

    提交

  • future

    已弃用; 此标志始终为 True。

    另请参阅

    SQLAlchemy 2.0 - 主要迁移指南

  • info – 可选的与此 Session 关联的任意数据的字典。 可通过 Session.info 属性访问。 请注意,该字典在构造时被复制,因此对每个 Session 字典的修改将局限于该 Session

  • query_cls – 应该用于创建新的查询对象的类,由 Session.query() 方法返回。 默认为 Query

  • twophase – 当为True时,所有事务都将作为“两阶段”事务启动,即使用正在使用的数据库的“两阶段”语义以及 XID。在每个附加数据库上发出了所有附加数据库的flush()之后,在commit()期间,将调用每个数据库的TwoPhaseTransactionTwoPhaseTransaction.prepare()方法。这允许每个数据库在提交每个事务之前回滚整个事务。

  • autocommitautocommit关键字出现是为了向后兼容,但必须保持其默认值为False

  • join_transaction_mode

    描述了在给定绑定是已经在此Session范围之外开始事务的Connection时要采取的事务行为;换句话说,Connection.in_transaction()方法返回 True。

    以下行为仅在Session实际使用给定的连接时才生效;也就是说,诸如Session.execute()Session.connection()等方法实际上被调用:

    • "conditional_savepoint" - 这是默认值。如果给定的Connection在事务中开始但没有保存点,则使用"rollback_only"。如果Connection此外还在保存点中,换句话说,Connection.in_nested_transaction()方法返回 True,则使用"create_savepoint"

      "conditional_savepoint" 行为试图利用 SAVEPOINT 以保持现有事务的状态不变,但只有在已经存在 SAVEPOINT 的情况下才会这样做;否则,不假定正在使用的后端具有足够的 SAVEPOINT 支持,因为此功能的可用性会有所变化。 "conditional_savepoint" 还试图与之前的 Session 行为建立大致的向后兼容性,适用于未设置特定模式的应用程序。建议使用其中一种显式设置。

    • "create_savepoint" - Session 将在所有情况下使用 Connection.begin_nested() 来创建自己的事务。该事务本质上“在顶部”上使用给定 Connection 上已打开的任何现有事务;如果底层数据库和正在使用的驱动程序完全且不破损地支持 SAVEPOINT,则外部事务将在 Session 的生命周期内保持不受影响。

      "create_savepoint" 模式对于将 Session 集成到测试套件中并使外部启动的事务保持不受影响是最有用的;但是,它依赖于底层驱动程序和数据库对 SAVEPOINT 的正确支持。

      提示

      当使用 SQLite 时,Python 3.11 中包含的 SQLite 驱动程序在某些情况下未正确处理 SAVEPOINTs,需要使用解决方法。详见 Serializable isolation / Savepoints / Transactional DDL 和 Serializable isolation / Savepoints / Transactional DDL (asyncio version) 部分。

    • "control_fully" - Session 将控制给定事务作为自己的事务; Session.commit() 将在事务上调用.commit()Session.rollback() 将在事务上调用.rollback()Session.close() 将调用事务上的.rollback

      提示

      此使用模式等同于 SQLAlchemy 1.4 处理具有现有 SAVEPOINT 的Connection的方式(即Connection.begin_nested()); Session将完全控制现有的 SAVEPOINT。

    • "rollback_only" - Session仅会接管给定事务的.rollback()调用;.commit()调用不会传播到给定事务。.close()调用不会对给定事务产生影响。

      提示

      此使用模式等同于 SQLAlchemy 1.4 处理具有现有常规数据库事务的Connection的方式(即Connection.begin());Session将传播Session.rollback()调用到底层事务,但不会传播Session.commit()Session.close()调用。

    自 2.0.0rc1 版本新增。

  • close_resets_only -

    默认为True。确定会话在调用.close()后是否应该重置自身,还是应该处于不再可用的状态,禁用重用。

    自 2.0.22 版本新增:添加标志close_resets_only。未来的 SQLAlchemy 版本可能会将此标志的默认值更改为False

    另请参阅

    关闭 - 关于Session.close()Session.reset()语义的详细信息。

method add(instance: object, _warn: bool = True) → None

将一个对象放入此Session中。

传递给Session.add()方法时处于瞬时状态的对象将移动到挂起状态,直到下一次刷新,然后它们将转移到持久化状态。

传递给Session.add()方法时处于分离状态的对象将直接转移到持久化状态。

如果由Session使用的事务被回滚,那些在传递给Session.add()时处于瞬态的对象将会被移回到瞬态状态,并且不再存在于这个Session中。

另请参见

Session.add_all()

添加新项目或现有项目 - 在使用会话的基础知识

method add_all(instances: Iterable[object]) → None

将给定的实例集合添加到此Session中。

请参阅Session.add()的文档以获取一般行为描述。

另请参见

Session.add()

添加新项目或现有项目 - 在使用会话的基础知识

method begin(nested: bool = False) → SessionTransaction

在此Session上开始事务或嵌套事务(如果尚未开始)。

Session对象具有autobegin行为,因此通常不需要显式调用Session.begin()方法。但是,它可以用来控制何时开始事务状态的范围。

当用于开始最外层事务时,如果此Session已经处于事务中,则会引发错误。

参数:

nested – 如果为 True,则开始一个 SAVEPOINT 事务,并等效于调用Session.begin_nested()。有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction对象。注意SessionTransaction充当 Python 上下文管理器,允许在“with”块中使用Session.begin()。请参阅显式开始以获取示例。

另请参见

自动开始

管理事务

Session.begin_nested()

method begin_nested() → SessionTransaction

在此Session上开始“嵌套”事务,例如 SAVEPOINT。

目标数据库和相关驱动程序必须支持 SQL SAVEPOINT,以使此方法正常工作。

有关 SAVEPOINT 事务的文档,请参阅 使用 SAVEPOINT。

返回:

SessionTransaction 对象。请注意,SessionTransaction 作为上下文管理器,允许在“with”块中使用 Session.begin_nested()。请参阅 使用 SAVEPOINT 获取使用示例。

另请参阅

使用 SAVEPOINT

可串行化隔离 / Savepoints / 事务性 DDL - 使用 SQLite 驱动程序时,为使 SAVEPOINT 正常工作需要特殊的解决方法。对于 asyncio 案例,请参阅 可串行化隔离 / Savepoints / 事务性 DDL(asyncio 版本) 部分。

method bind_mapper(mapper: _EntityBindKey[_O], bind: _SessionBind) → None

Mapper 或任意 Python 类与“bind”关联,例如一个 EngineConnection

给定的实体被添加到 Session.get_bind() 方法使用的查找中。

参数:

  • mapper – 一个 Mapper 对象,或者一个映射类的实例,或者任何作为一组映射类基础的 Python 类。

  • bind – 一个 EngineConnection 对象。

另请参阅

分区策略(例如,每个 Session 多个数据库后端)

Session.binds

Session.bind_table()

method bind_table(table: TableClause, bind: Engine | Connection) → None

Table 与“bind”关联,例如一个 EngineConnection

给定的 Table 被添加到 Session.get_bind() 方法使用的查找中。

参数:

  • table – 一个 Table 对象,通常是 ORM 映射的目标,或者存在于可选择的映射中。

  • bind - 一个EngineConnection对象。

另请参阅

分区策略(例如每个 Session 的多个数据库后端)

Session.binds

Session.bind_mapper()

method bulk_insert_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]], return_defaults: bool = False, render_nulls: bool = False) → None

执行给定映射字典列表的批量插入。

传统特性

该方法是 SQLAlchemy 2.0 系列的一个传统特性。对于现代的批量插入和更新,请参见 ORM 批量插入语句和 ORM 按主键批量更新部分。2.0 API 共享了与该方法的实现细节,并添加了新的特性。

参数:

  • mapper - 一个映射类,或者实际的Mapper对象,表示映射列表中所代表的单一对象种类。

  • mappings - 一系列字典,每个字典包含要插入的映射行的状态,以映射类上的属性名称表示。如果映射涉及多个表,例如连接继承映射,则每个字典必须包含要填充到所有表中的所有键。

  • return_defaults -

    当为 True 时,INSERT 过程将被修改以确保新生成的主键值将被获取。该参数的理由通常是为了使连接表继承映射能够批量插入。

    注意

    对于不支持 RETURNING 的后端,Session.bulk_insert_mappings.return_defaults参数可能会显著降低性能,因为 INSERT 语句无法再批量处理。有关受影响的后端的背景信息,请参阅 INSERT 语句的“插入多个值”行为。

  • render_nulls -

    当为 True 时,None值将导致在 INSERT 语句中包含一个 NULL 值,而不是将列从 INSERT 中省略。这允许所有被 INSERT 的行具有相同的列集,从而允许将完整的行集批量发送到 DBAPI。通常,每个包含与上一行不同的 NULL 值组合的列集必须从渲染的 INSERT 语句中省略不同的列系列,这意味着必须作为单独的语句发出。通过传递此标志,可以确保将完整的行集批量处理为一个批次;但成本是,通过省略列调用的服务器端默认值将被跳过,因此必须注意确保这些不是必需的。

    警告

    当设置此标志时,不会调用服务器端默认的 SQL 值,对于那些作为 NULL 插入的列;NULL 值将被显式发送。必须注意确保整个操作不需要调用服务器端默认函数。

另请参阅

启用 ORM 的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_save_objects()

Session.bulk_update_mappings()

method bulk_save_objects(objects: Iterable[object], return_defaults: bool = False, update_changed_only: bool = True, preserve_order: bool = True) → None

对给定对象列表执行批量保存。

传统功能

该方法是 SQLAlchemy 2.0 系列的传统功能。对于现代的批量 INSERT 和 UPDATE,请参见 ORM 批量 INSERT 语句和 ORM 按主键批量 UPDATE 部分。

对于一般的 INSERT 和 UPDATE 现有 ORM 映射对象,建议使用标准的工作单元数据管理模式,介绍在 SQLAlchemy 统一教程中的 ORM 数据操作。SQLAlchemy 2.0 现在使用现代方言的“Insert Many Values”行为用于 INSERT 语句,解决了以前批量 INSERT 速度慢的问题。

参数:

  • objects

    映射对象实例的序列。映射对象按原样持久化,并且之后Session关联。

    对于每个对象,无论对象是作为 INSERT 还是 UPDATE 发送的,都取决于传统操作中Session使用的相同规则;如果对象具有InstanceState.key属性设置,则假定对象为“分离”,将导致 UPDATE。否则,将使用 INSERT。

    在 UPDATE 的情况下,语句根据哪些属性已更改而分组,并因此成为每个 SET 子句的主题。如果update_changed_only为 False,则每个对象中存在的所有属性都将应用于 UPDATE 语句,这有助于将语句组合成更大的 executemany(),并且还将减少检查属性历史的开销。

  • return_defaults - 当为 True 时,缺少生成默认值的值的行,即整数主键默认值和序列,将逐个插入,以便主键值可用。特别是,这将允许加入继承和其他多表映射正确插入,而无需提前提供主键值;但是,Session.bulk_save_objects.return_defaults会大大降低该方法的性能增益。强烈建议使用标准的Session.add_all()方法。

  • update_changed_only - 当为 True 时,根据每个状态中已记录更改的属性来渲染 UPDATE 语句。当为 False 时,所有存在的属性都将渲染到 SET 子句中,除了主键属性。

  • preserve_order - 当为 True 时,插入和更新的顺序与给定对象的顺序完全匹配。当为 False 时,常见类型的对象被分组为插入和更新,以便提供更多的批处理机会。

另请参阅

ORM 启用的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_update_mappings()

method bulk_update_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]) → None

对给定的映射字典列表执行批量更新。

传统特性

该方法是 SQLAlchemy 2.0 系列的一个传统特性。对于现代的批量 INSERT 和 UPDATE,请参见 ORM 批量 INSERT 语句和 ORM 按主键批量 UPDATE 部分。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:

  • mapper - 一个映射类,或者实际的Mapper对象,表示映射列表中表示的单一对象类型。

  • mappings - 一个字典序列,每个字典包含要更新的映射行的状态,以映射类上的属性名称表示。如果映射涉及多个表,比如联接继承映射,每个字典可能包含与所有表对应的键。所有存在且不是主键的键将应用于 UPDATE 语句的 SET 子句;需要的主键值将应用于 WHERE 子句。

另请参见

ORM-Enabled INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_save_objects()

method close() → None

结束由此 Session 使用的事务资源和 ORM 对象。

这会清除与此 Session 关联的所有 ORM 对象,结束任何正在进行的事务,并释放此 Session 从相关 Engine 对象中检出的任何 Connection 对象。然后,该操作将 Session 置于可以再次使用的状态。

提示

在默认运行模式下,Session.close() 方法不会阻止该 Session 再次使用Session 本身实际上并没有一个独立的“关闭”状态;它只是意味着 Session 将释放所有数据库连接和 ORM 对象。

将参数 Session.close_resets_only 设置为 False 将使 close 最终化,这意味着会禁止对会话的任何进一步操作。

从 1.4 版本开始变更:Session.close() 方法不会立即创建一个新的 SessionTransaction 对象;相反,只有在再次使用 Session 进行数据库操作时才会创建新的 SessionTransaction

另请参见

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.reset() - 一种类似的方法,其行为类似于close(),参数为Session.close_resets_only设置为True

classmethod close_all() → None

继承自 sqlalchemy.orm.session._SessionClassMethods.close_all 方法的 sqlalchemy.orm.session._SessionClassMethods

关闭所有内存中的会话。

自版本 1.3 起已弃用:Session.close_all()方法已弃用,将在将来的版本中删除。请参考close_all_sessions()

method commit() → None

刷新待处理的更改并提交当前事务。

当 COMMIT 操作完成时,所有对象都完全过期,擦除其内部内容,当下次访问这些对象时,将自动重新加载。在此期间,这些对象处于过期状态,并且如果从Session中分离出来,则不会起作用。此外,当使用基于 asyncio 的 API 时,不支持此重新加载操作。Session.expire_on_commit参数可用于禁用此行为。

Session中没有事务时,表示自上次调用Session.commit()以来没有对此Session执行任何操作时,该方法将开始并提交一个仅内部的“逻辑”事务,通常不会影响数据库,除非检测到有待提交的刷新更改,但仍然会调用事件处理程序和对象过期规则。

最外层的数据库事务会无条件提交,自动释放任何生效的 SAVEPOINT。

另请参阅

提交

管理事务

在使用 AsyncSession 时避免隐式 IO

method connection(bind_arguments: _BindArguments | None = None, execution_options: CoreExecuteOptionsParameter | None = None) → Connection

返回一个与该Session对象的事务状态对应的Connection对象。

返回当前事务对应的 Connection,或者如果没有进行中的事务,则开始新的事务并返回 Connection(请注意,在第一个 SQL 语句被发出之前,与 DBAPI 之间不会建立事务状态)。

多重绑定或未绑定的 Session 对象中的歧义可以通过任何可选关键字参数解决。最终将使用 get_bind() 方法进行解决。

参数:

  • bind_arguments – 绑定参数字典。可能包括“mapper”,“bind”,“clause”等其他传递给 Session.get_bind() 的自定义参数。

  • execution_options

    一个执行选项字典,当首次获得连接时将传递给 Connection.execution_options()。如果连接已经存在于 Session 中,将发出警告并忽略参数。

    另请参阅

    设置事务隔离级别 / DBAPI AUTOCOMMIT

method delete(instance: object) → None

将实例标记为已删除。

假设传入的对象在调用该方法后处于 持久化 或 分离 状态;在此方法被调用后,对象将保持 持久化 状态,直到下一次刷新操作进行。在此期间,该对象也将是 Session.deleted 集合的成员。

当下一次刷新操作进行时,对象将移动到 已删除 状态,表示在当前事务中为其行发出了 DELETE 语句。当事务成功提交时,已删除对象将移动到 分离 状态,并且不再存在于此 Session 中。

另请参阅

删除 - 在 使用会话的基础知识

attribute deleted

所有在此 Session 中标记为 ‘deleted’ 的实例集合。

attribute dirty

所有被认为是脏的持久化实例集合。

例如:

some_mapped_object in session.dirty

当实例被修改但未删除时被视为脏。

请注意,此“脏”计算是“乐观”的;大多数属性设置或集合修改操作都将将实例标记为“脏”,并将其放入此集合中,即使属性的值没有净变化。在刷新时,将每个属性的值与其先前保存的值进行比较,如果没有净变化,则不会执行任何 SQL 操作(这是一项更昂贵的操作,因此仅在刷新时执行)。

要检查实例是否有可操作的净变化来修改其属性,请使用Session.is_modified()方法。

method enable_relationship_loading(obj: object) → None

将对象与此Session关联以进行相关对象加载。

警告

enable_relationship_loading()存在以服务于特殊用例,并不建议用于一般用途。

使用relationship()映射的属性的访问将尝试使用此Session作为连接源从数据库加载值。值将根据此对象上存在的外键和主键值加载 - 如果不存在,则这些关系将不可用。

对象将附加到此会话,但不会参与任何持久性操作;它的状态对于几乎所有目的都将保持“瞬态”或“分离”,除了关系加载的情况。

还要注意,反向引用通常不会按预期工作。如果目标对象上的关系绑定属性发生更改,则可能不会触发反向引用事件,如果有效值已从保存外键值的值中加载,则不会触发事件。

Session.enable_relationship_loading()方法类似于relationship()上的load_on_pending标志。与该标志不同,Session.enable_relationship_loading()允许对象保持瞬态,同时仍然能够加载相关项目。

要使一个临时对象与Session相关联,可以通过Session.enable_relationship_loading()将其添加到Session中。如果该对象代表数据库中现有的标识,则应使用Session.merge()进行合并。

当 ORM 正常使用时,Session.enable_relationship_loading()不会改善行为 - 对象引用应该在对象级别而不是在外键级别构建,以便它们在 flush()继续之前以普通方式存在。此方法不适用于一般用途。

另请参见

relationship.load_on_pending - 此标志允许在待处理项目上对多对一进行每关系加载。

make_transient_to_detached() - 允许将对象添加到Session中而不发出 SQL,然后在访��时取消过期属性。

method execute(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, _parent_execute_state: Any | None = None, _add_event: Any | None = None) → Result[Any]

执行一个 SQL 表达式构造。

返回一个代表语句执行结果的Result对象。

例如:

from sqlalchemy import select
result = session.execute(
    select(User).where(User.id == 5)
)

Session.execute()的 API 契约类似于Connection.execute()的契约,是Connection的 2.0 风格版本。

从版本 1.4 开始更改:当使用 2.0 风格的 ORM 用法时,Session.execute()方法现在是 ORM 语句执行的主要点。

参数:

  • statement – 一个可执行的语句(即一个Executable表达式,如select())。

  • params – 可选字典,或包含绑定参数值的字典列表。如果是单个字典,则执行单行; 如果是字典列表,则将调用“executemany”。每个字典中的键必须与语句中存在的参数名称相对应。

  • execution_options

    可选的执行选项字典,将与语句执行相关联。此字典可以提供Connection.execution_options()接受的选项的子集,并且还可以提供仅在 ORM 上下文中理解的其他选项。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments – 用于确定绑定的其他参数字典。可以包括“mapper”,“bind”或其他自定义参数。此字典的内容将传递给Session.get_bind()方法。

返回:

一个Result对象。

method expire(instance: object, attribute_names: Iterable[str] | None = None) → None

使实例上的属性过期。

标记实例的属性为过期。下次访问过期属性时,将向Session对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与该事务中先前读取的相同值,而不管该事务外的数据库状态发生了什么变化。

要同时使Session中的所有对象过期,请使用Session.expire_all()

当调用Session.rollback()Session.commit()方法时,Session对象的默认行为是使所有状态过期,以便为新事务加载新状态。因此,仅在当前事务中发出非 ORM SQL 语句的特定情况下调用Session.expire()才有意义。

参数:

  • instance – 要刷新的实例。

  • attribute_names – 可选的字符串属性名称列表,指示要过期的属性子集。

另请参阅

刷新/过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expire_all() → None

使此会话中的所有持久实例过期。

下次访问持久实例上的任何属性时,将使用Session对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与之前在同一事务中读取的相同值,而不考虑该事务之外的数据库状态的更改。

要使个别对象和这些对象上的个别属性过期,请使用Session.expire()

当调用Session.rollback()Session.commit()方法时,默认情况下,Session对象会将所有状态过期,以便为新的事务加载新的状态。因此,通常不需要调用Session.expire_all(),假设事务是隔离的。

另请参阅

刷新 / 过期 - 入门材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expunge(instance: object) → None

从这个Session中移除实例。

这将释放对该实例的所有内部引用。根据expunge级联规则将应用级联。

method expunge_all() → None

从这个Session中移除所有对象实例。

这相当于在这个Session中调用expunge(obj)来移除所有对象。

method flush(objects: Sequence[Any] | None = None) → None

刷新所有对象更改到数据库。

将所有待定的对象创建、删除和修改写入数据库,作为 INSERT、DELETE、UPDATE 等操作。操作会自动按照会话的工作单元依赖解决器进行排序。

数据库操作将在当前事务上下文中发出,并且不会影响事务的状态,除非发生错误,此时整个事务都会回滚。在事务中随时可以刷新(flush())以将更改从 Python 移动到数据库的事务缓冲区。

参数:

对象

可选;限制刷新操作仅对给定集合中存在的元素进行操作。

这个功能适用于极少数情况,特定对象可能需要在完全刷新(flush())之前进行操作。它不适用于一般用途。

method get(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O | None

返回基于给定主键标识符的实例,如果找不到则返回None

例如:

my_user = session.get(User, 5)

some_object = session.get(VersionedFoo, (5, 10))

some_object = session.get(
    VersionedFoo,
    {"id": 5, "version_id": 10}
)

从版本 1.4 开始:添加了Session.get(),该方法已从现在过时的Query.get()方法中移动。

Session.get()是特殊的,因为它直接提供了对Session的标识映射的访问。如果给定的主键标识符存在于本地标识映射中,则直接从该集合返回对象,而不会发出任何 SQL,除非对象已被标记为完全过期。如果不存在,则执行 SELECT 以定位对象。

Session.get()还将执行检查,如果对象存在于标识映射中并标记为过期,则发出 SELECT 以刷新对象以及确保行仍然存在。如果不存在,则引发ObjectDeletedError

参数:

  • entity – 表示要加载的实体类型的映射类或Mapper

  • ident

    表示主键的标量、元组或字典。对于复合(例如,多列)主键,应传递元组或字典。

    对于单列主键,标量调用形式通常是最方便的。如果行的主键是值“5”,调用如下所示:

    my_object = session.get(SomeClass, 5)
    

    元组形式包含主键值,通常按照它们与映射的Table对象的主键列对应的顺序排列,或者如果使用了Mapper.primary_key配置参数,则按照该参数的顺序排列。例如,如果行的主键由整数数字“5,10”表示,则调用如下所示:

    my_object = session.get(SomeClass, (5, 10))
    

    字典形式应包含作为主键每个元素相应的映射属性名称的键。如果映射类具有存储对象主键值的属性idversion_id,则调用如下所示:

    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
    
  • options – 可选的加载器选项序列,将应用于查询(如果有的话)。

  • populate_existing – 导致该方法无条件地发出 SQL 查询,并使用新加载的数据刷新对象,无论对象是否已存在。

  • with_for_update – 可选的布尔值True,表示应使用 FOR UPDATE,或者可以是一个包含用于指示 SELECT 的更具体的一组 FOR UPDATE 标志的字典;标志应与Query.with_for_update()参数的参数相匹配。取代Session.refresh.lockmode参数。

  • execution_options

    可选的执行选项字典,如果发出了查询执行,则将其与查询执行相关联。该字典可以提供Connection.execution_options()接受的选项的子集,并且还可以提供只有在 ORM 上下文中理解的其他选项。

    1.4.29 版中新增。

    另请参阅

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments

    用于确定绑定的其他参数的字典。可能包括“mapper”、“bind”或其他自定义参数。该字典的内容将传递给Session.get_bind()方法。

返回:

对象实例,或None

method get_bind(mapper: _EntityBindKey[_O] | None = None, *, clause: ClauseElement | None = None, bind: _SessionBind | None = None, _sa_skip_events: bool | None = None, _sa_skip_for_implicit_returning: bool = False, **kw: Any) → Engine | Connection

返回此Session绑定到的“bind”。

“bind”通常是Engine的实例,除非Session已被明确地直接绑定到Connection的情况。

对于多次绑定或未绑定的Session,使用mapperclause参数来确定返回的适当绑定。

注意当通过 ORM 操作调用Session.get_bind()时通常存在“mapper”参数,例如Session.query()中的每个个体 INSERT/UPDATE/DELETE 操作,Session.flush()调用等。

解析顺序为:

  1. 如果给定了mapper并且Session.binds存在,则首先基于正在使用的映射器,然后基于正在使用的映射类,然后基于映射类的__mro__中存在的任何基类,从更具体的超类到更一般的类来定位一个绑定。

  2. 如果给定了条件并且Session.binds存在,则基于Session.binds中的给定条件中找到的Table对象定位绑定。

  3. 如果Session.binds存在,则返回该绑定。

  4. 如果给定了条件,则尝试返回与该条件最终关联的MetaData绑定。

  5. 如果提供了映射器,尝试返回与最终与该映射器映射的Table或其他可选择对象关联的MetaData绑定。

  6. 如果找不到绑定,则会引发UnboundExecutionError

请注意,Session.get_bind()方法可以在Session的用户定义子类上被重写,以提供任何类型的绑定解析方案。请参阅自定义垂直分区中的示例。

参数:

  • mapper – 可选的映射类或相应的Mapper实例。绑定可以首先从此Session关联的“绑定”映射中派生,其次是从该Mapper映射到的Table关联的MetaData中派生。

  • clause – 一个ClauseElement(即select()text()等)。如果mapper参数不存在或无法生成绑定,则将搜索给定的表达式构造,通常是与绑定的MetaData关联的Table

另请参阅

分区策略(例如每个会话的多个数据库后端)

Session.binds

Session.bind_mapper()

Session.bind_table()

method get_nested_transaction() → SessionTransaction | None

返回正在进行的当前嵌套事务(如果有)。

新版本 1.4 中新增。

method get_one(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O

根据给定的主键标识符返回精确的一个实例,如果未找到则引发异常。

如果查询未选择任何行,则引发sqlalchemy.orm.exc.NoResultFound

有关参数的详细文档,请参阅方法Session.get()

新版本 2.0.22 中新增。

返回:

对象实例。

另请参见

Session.get() - 相当的方法,代替

如果未找到具有提供的主键的行,则返回None

method get_transaction() → SessionTransaction | None

返回正在进行的当前根事务(如果有)。

新版本 1.4 中新增。

classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

继承自 sqlalchemy.orm.session._SessionClassMethods.identity_key 的方法 sqlalchemy.orm.session._SessionClassMethods

返回一个标识键。

这是 identity_key() 的别名。

attribute identity_map: IdentityMap

对象标识到对象本身的映射。

通过Session.identity_map.values()迭代提供对当前会话中当前持久对象(即具有行标识的对象)的完整集合的访问。

另请参见

identity_key() - 辅助函数,用于生成此字典中使用的键。

method in_nested_transaction() → bool

如果此 Session 已开始嵌套事务(例如,SAVEPOINT),则返回 True。

新版本 1.4 中新增。

method in_transaction() → bool

如果此 Session 已开始事务,则返回 True。

新版本 1.4 中新增。

另请参见

Session.is_active

attribute info

一个用户可修改的字典。

此字典的初始值可以使用 info 参数来填充到 Session 构造函数或 sessionmaker 构造函数或工厂方法中。此处的字典始终局限于此 Session 并且可以独立于所有其他 Session 对象进行修改。

method invalidate() → None

关闭此会话,使用连接失效。

这是 Session.close() 的变体,还将确保对每个当前用于事务的 Connection 对象调用 Connection.invalidate() 方法(通常只有一个连接,除非 Session 与多个引擎一起使用)。

当已知数据库处于不再安全使用连接的状态时,可以调用此方法。

以下示例说明了在使用 gevent 时可能出现的可导致底层连接应被丢弃的 Timeout 异常情况:

import gevent

try:
    sess = Session()
    sess.add(User())
    sess.commit()
except gevent.Timeout:
    sess.invalidate()
    raise
except:
    sess.rollback()
    raise

此方法还会执行 Session.close() 所做的所有操作,包括清除所有 ORM 对象。

attribute is_active

如果此 Session 未处于“部分回滚”状态,则返回 True。

版本 1.4 中的更改:Session 不再立即开始新事务,因此当首次实例化 Session 时,此属性将为 False。

“部分回滚”状态通常表示 Session 的刷新过程失败,并且必须发出 Session.rollback() 方法以完全回滚事务。

如果此 Session 未处于事务中,则当首次使用时,Session 将自动开始,因此在这种情况下,Session.is_active 将返回 True。

否则,如果此 Session 处于事务中,并且该事务尚未在内部回滚,则 Session.is_active 也将返回 True。

另请参阅

“由于刷新期间的先前异常,此会话的事务已回滚。”(或类似内容)

Session.in_transaction()

method is_modified(instance: object, include_collections: bool = True) → bool

如果给定实例具有本地修改的属性,则返回 True

此方法检索实例上每个受仪器化的属性的历史记录,并将当前值与其先前提交的值进行比较(如果有)。

实际上,这是检查 Session.dirty 集合中给定实例的更昂贵和准确的版本;对每个属性的净“脏”状态进行全面测试。

例如:

return session.is_modified(someobject)

这种方法有一些注意事项:

  • Session.dirty 集合中存在的实例在使用此方法进行测试时可能会报告 False。这是因为对象可能通过属性突变接收到更改事件,从而将其置于 Session.dirty 中,但最终状态与从数据库加载的状态相同,在这里没有净更改。

  • 当新值被应用时,标量属性可能没有记录先前设置的值,如果在接收新值时该属性未加载或已过期,则假定该属性有一个更改,即使最终对其数据库值没有净更改也是如此。在这些情况下,即使最终没有针对数据库值的净更改,也假定该属性有一个更改。在大多数情况下,当发生 set 事件时,SQLAlchemy 不需要“旧”值,因此如果旧值不存在,则跳过 SQL 调用的开销,这是基于标量值通常需要 UPDATE 的假设,并且在那几种情况下它不需要的情况下,平均比发出防御性的 SELECT 更便宜。

    仅当属性容器的 active_history 标志设置为 True 时,才无条件地在 set 时获取“旧”值。这个标志通常设置为主键属性和不是简单多对一的标量对象引用。要为任意映射列设置此标志,请使用 column_property()active_history 参数。

参数:

  • instance – 被测试的映射实例。

  • include_collections – 表示是否应包含多值集合在操作中。将其设置为 False 是一种检测仅基于本地列的属性(即标量列或多对一外键),这些属性会导致此实例在刷新时进行 UPDATE 的方法。

method merge(instance: _O, *, load: bool = True, options: Sequence[ORMOption] | None = None) → _O

将给定实例的状态复制到此 Session 中的相应实例。

Session.merge()检查源实例的主键属性,并尝试将其与会话中具有相同主键的实例进行协调。如果在本地找不到,则尝试根据主键从数据库加载对象,如果找不到,则创建一个新实例。然后将源实例上的每个属性的状态复制到目标实例。然后该方法返回生成的目标实例;原始源实例保持不变,并且如果尚未与Session相关联,则不与之相关联。

如果关联使用cascade="merge"进行映射,则此操作会级联到关联的实例。

有关合并的详细讨论,请参见合并。

参数:

  • instance – 要合并的实例。

  • load

    布尔值,当为 False 时,merge()切换到“高性能”模式,使其放弃发出历史事件以及所有数据库访问。此标志用于诸如将对象图传输到从第二级缓存中的Session中,或者将刚加载的对象传输到由工作线程或进程拥有的Session中,而无需重新查询数据库的情况。

    load=False用例增加了这样一个警告,即给定对象必须处于“干净”状态,也就是说,没有要刷新的挂起更改-即使传入对象已从任何Session分离。这样,当合并操作填充本地属性并级联到相关对象和集合时,值可以原样“打印”到目标对象上,而不会生成任何历史记录或属性事件,并且无需将传入数据与可能未加载的任何现有相关对象或集合进行协调。来自load=False的结果对象始终生成为“干净”,因此只有给定对象也应该是“干净”的,否则这表明方法的错误使用。

  • options

    在合并操作从数据库加载对象的现有版本时,会将一系列可选的加载器选项应用于Session.get()方法。

    版本 1.4.24 中的新功能。

另请参见

make_transient_to_detached() - 提供了一种将单个对象“合并”到Session中的替代方法

attribute new

在此Session中标记为“new”的所有实例的集合。

attribute no_autoflush

返回一个禁用自动刷新的上下文管理器。

例如:

with session.no_autoflush:

    some_object = SomeClass()
    session.add(some_object)
    # won't autoflush
    some_object.related_thing = session.query(SomeRelated).first()

with: 块内进行的操作不会受到在查询访问时发生的刷新的影响。当初始化一系列涉及现有数据库查询的对象时,尚未完成的对象不应立即被刷新时,这是有用的。

classmethod object_session(instance: object) → Session | None

继承自 sqlalchemy.orm.session._SessionClassMethods.object_session 方法的 sqlalchemy.orm.session._SessionClassMethods

返回一个对象所属的 Session

这是 object_session() 的别名。

method prepare() → None

准备当前进行中的事务以进行两阶段提交。

如果没有进行事务,则此方法会引发一个 InvalidRequestError

仅两阶段会话的根事务可以被准备。如果当前事务不是这样的事务,则会引发一个 InvalidRequestError

method query(*entities: _ColumnsClauseArgument[Any], **kwargs: Any) → Query[Any]

返回一个与此 Session 对应的新 Query 对象。

请注意,Query 对象自 SQLAlchemy 2.0 起已被视为遗留;现在使用 select() 构造 ORM 查询。

另请参阅

SQLAlchemy 统一教程

ORM 查询指南

遗留查询 API - 遗留 API 文档

method refresh(instance: object, attribute_names: Iterable[str] | None = None, with_for_update: ForUpdateParameter = None) → None

使给定实例的属性过期并刷新。

首先将选定的属性作为当使用 Session.expire() 时会过期的那样进行过期处理;然后将发出 SELECT 语句到数据库,以使用当前事务中可用的当前值刷新基于列的属性。

如果对象已经被急切加载,那么 relationship() 定向属性也将立即被加载,使用它们最初加载时使用的急切加载策略。

版本 1.4 中的新功能:- Session.refresh() 方法也可以刷新急切加载的属性。

relationship() 导向属性通常会使用 select(或“延迟加载”)加载策略,如果它们在 attribute_names 集合中被明确命名,也会加载**,使用 immediate 加载策略对属性发出 SELECT 语句。如果惰性加载的关系未在Session.refresh.attribute_names中命名,则它们保持为“惰性加载”属性,不会被隐式刷新。

在版本 2.0.4 中更改:Session.refresh() 方法现在将刷新那些在Session.refresh.attribute_names集合中明确命名的惰性加载的relationship() 导向属性。

提示

虽然 Session.refresh() 方法能够刷新列和关系导向的属性,但其主要重点是在单个实例上刷新本地列导向的属性。要获得更开放的“刷新”功能,包括能够同时刷新许多对象的属性并明确控制关系加载策略,请使用 populate existing 功能。

请注意,高度隔离的事务将返回与在同一事务中先前读取的值相同的值,而不管该事务之外的数据库状态是否发生了变化。通常仅在事务开始时,尚未访问数据库行时刷新属性才有意义。

参数:

  • attribute_names – 可选。一个字符串属性名称的可迭代集合,指示要刷新的属性的子集。

  • with_for_update – 可选布尔值 True,指示是否应使用 FOR UPDATE,或者可能是一个包含标志的字典,用于指示更具体的 FOR UPDATE 标志集合用于 SELECT;标志应该与 Query.with_for_update() 的参数匹配。取代Session.refresh.lockmode 参数。

另请参阅

刷新/过期 - 初级材料

Session.expire()

Session.expire_all()

填充现有对象 - 允许任何 ORM 查询刷新对象,就像它们通常加载的那样。

method reset() → None

关闭此Session使用的事务资源和 ORM 对象,将会话重置为其初始状态。

此方法提供了与Session.close()方法在历史上提供的相同的“仅重置”行为,其中Session的状态被重置,就像对象是全新的一样,准备好再次使用。然后,此方法可能对将Session.close_resets_only设置为FalseSession对象有用,以便仍然可以使用“仅重置”行为。

新版本 2.0.22。

另请参阅

关闭 - 详细介绍了 Session.close()Session.reset() 的语义。

Session.close() - 当参数 Session.close_resets_only 设置为 False 时,此类方法还将阻止会话的重复使用。

method rollback() → None

回滚当前进行中的事务。

如果没有进行中的事务,则此方法是一个直通方法。

该方法始终回滚最顶层的数据库事务,丢弃可能正在进行的任何嵌套事务。

另请参阅

回滚

事务管理

method scalar(statement: Executable, params: _CoreSingleExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → Any

执行一条语句并返回一个标量结果。

用法和参数与Session.execute()相同;返回结果是一个标量 Python 值。

method scalars(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → ScalarResult[Any]

执行一条语句并将结果作为标量返回。

用法和参数与Session.execute()相同;返回结果是一个ScalarResult过滤对象,它将返回单个元素而不是Row对象。

返回:

一个ScalarResult对象

新版本 1.4.24 中添加:Session.scalars()

新版本 1.4.26 中添加:scoped_session.scalars()

另请参阅

选择 ORM 实体 - 将 Session.execute() 的行为与 Session.scalars() 进行对比

class sqlalchemy.orm.SessionTransaction

一个 Session 级别的事务。

SessionTransaction 是由 Session.begin()Session.begin_nested() 方法生成的。它在现代用法中主要是一个内部对象,为会话事务提供上下文管理器。

SessionTransaction 交互的文档位于:管理事务。

自版本 1.4 更改:直接处理 SessionTransaction 对象的范围和 API 方法已经简化。

另请参阅

管理事务

Session.begin()

Session.begin_nested()

Session.rollback()

Session.commit()

Session.in_transaction()

Session.in_nested_transaction()

Session.get_transaction()

Session.get_nested_transaction()

成员

嵌套, 原始, 父级

类签名

sqlalchemy.orm.SessionTransaction (sqlalchemy.orm.state_changes._StateChange, sqlalchemy.engine.util.TransactionalContext)

attribute nested: bool = False

指示这是否为嵌套或 SAVEPOINT 事务。

SessionTransaction.nested 为 True 时,预计 SessionTransaction.parent 也会出现,链接到封闭的 SessionTransaction

另请参见

SessionTransaction.origin

attribute origin: SessionTransactionOrigin

SessionTransaction 的来源。

指的是一个 SessionTransactionOrigin 实例,该实例是指导致构造此 SessionTransaction 的源事件的枚举。

新版本 2.0 中添加。

attribute parent

SessionTransaction 的父级 SessionTransaction

如果此属性为 None,表示此 SessionTransaction 位于堆栈顶部,并且对应于真实的 “COMMIT”/”ROLLBACK” 块。如果非 None,则这是一个 “子事务”(由刷新进程使用的内部标记对象)或 “嵌套” / SAVEPOINT 事务。如果 SessionTransaction.nested 属性为 True,则这是一个 SAVEPOINT,如果为 False,表示这是一个子事务。

class sqlalchemy.orm.SessionTransactionOrigin

表示SessionTransaction的来源。

此枚举存在于任何 SessionTransaction 对象的 SessionTransaction.origin 属性上。

新版本 2.0 中添加。

成员

AUTOBEGIN, BEGIN, BEGIN_NESTED, SUBTRANSACTION

类签名

sqlalchemy.orm.SessionTransactionOrigin (enum.Enum)

attribute AUTOBEGIN = 0

通过自动开始开始的事务

attribute BEGIN = 1

通过调用 Session.begin() 开始事务。

attribute BEGIN_NESTED = 2

通过 Session.begin_nested() 开始事务。

attribute SUBTRANSACTION = 3

事务是内部的 “子事务”

会话工具

对象名称 描述
close_all_sessions() 关闭内存中的所有会话。
make_transient(instance) 修改给定实例的状态,使其为瞬态。
make_transient_to_detached(instance) 使给定的瞬态实例成为脱离的。
object_session(instance) 返回给定实例所属的 Session
was_deleted(object_) 如果给定对象在会话刷新中被删除,则返回 True。
function sqlalchemy.orm.close_all_sessions() → None

关闭内存中的所有会话。

此函数会查询所有 Session 对象的全局注册表,并对它们调用 Session.close() ,将它们重置为干净的状态。

此函数不适用于一般用途,但在拆卸方案中的测试套件中可能有用。

版本 1.3 中的新功能。

function sqlalchemy.orm.make_transient(instance: object) → None

改变给定实例的状态,使其成为瞬态的。

注意

make_transient() 是仅用于高级用例的特殊情况函数。

假定给定的映射实例处于持久的或脱离的状态。 该函数将删除其与任何 Session 的关联以及其 InstanceState.identity。 其效果是对象将表现得像它是新构造的,除了保留在调用时加载的任何属性/集合值。 如果此对象已因使用 Session.delete() 而被删除,则还将重置 InstanceState.deleted 标志。

警告

make_transient() “取消过期”或以其他方式急切加载目前未加载的 ORM 映射属性。 这包括:

  • 通过 Session.expire() 过期

  • 由于提交会话事务的自然效果,会话过期,例如 Session.commit()

  • 通常是惰性加载,但目前未加载

  • 是“延迟加载”(参见 限制哪些列与列延迟加载)并且尚未加载

  • 在加载此对象的查询中不存在,例如,在连接表继承和其他场景中常见的情况下。

在调用make_transient()之后,通常会解析为None的未加载属性,例如上面的属性,或者是针对集合导向属性的空集合。 由于对象是临时的,并且与任何数据库标识都没有关联,因此将不再检索这些值。

另请参阅

make_transient_to_detached()

function sqlalchemy.orm.make_transient_to_detached(instance: object) → None

使给定的临时实例脱离。

注意

make_transient_to_detached()是一个仅用于高级用例的特殊情况函数。

给定实例的所有属性历史记录都将被重置,就好像该实例是从查询中新加载的一样。 缺少的属性将被标记为过期。 对象的主键属性将被制成实例的“键”,这些主键属性是必需的。

然后可以将对象添加到会话中,或者可能与 load=False 标志合并,此时它看起来就像是以这种方式加载的,而不会发出 SQL。

这是一个特殊的用例函数,它与对Session.merge()的普通调用不同,因为可以在不进行任何 SQL 调用的情况下制造给定的持久状态。

另请参阅

make_transient()

Session.enable_relationship_loading()

function sqlalchemy.orm.object_session(instance: object) → Session | None

返回给定实例所属的Session

这基本上与InstanceState.session访问器相同。 有关详细信息,请参阅该属性。

function sqlalchemy.orm.util.was_deleted(object_: object) → bool

如果给定对象在会话刷新时被删除,则返回 True。

无论对象是否持久还是分离,都是如此。

另请参阅

InstanceState.was_deleted

属性和状态管理工具

这些函数由 SQLAlchemy 属性检测 API 提供,用于提供详细的接口来处理实例、属性值和历史记录。 在构建事件监听器函数时,其中一些函数非常有用,例如在 ORM 事件中描述的函数。

对象名称 描述
del_attribute(instance, key) 删除属性的值,并触发历史事件。
flag_dirty(instance) 标记一个实例为“脏”,而不具体提到任何属性。
flag_modified(instance, key) 将实例上的属性标记为“修改”。
get_attribute(instance, key) 获取属性的值,触发任何所需的可调用对象。
get_history(obj, key[, passive]) 为给定对象和属性键返回一个History 记录。
History 添加、未更改和已删除值的三元组,表示在工具化属性上发生的更改。
init_collection(obj, key) 初始化集合属性并返回集合适配器。
instance_state 返回给定映射对象的InstanceState
is_instrumented(instance, key) 如果给定实例的给定属性由 attributes 包进行了工具化,则返回 True。
object_state(instance) 给定一个对象,返回与该对象关联的InstanceState
set_attribute(instance, key, value[, initiator]) 设置属性的值,触发历史事件。
set_committed_value(instance, key, value) 设置属性的值,没有历史事件。
function sqlalchemy.orm.util.object_state(instance: _T) → InstanceState[_T]

给定一个对象,返回与该对象关联的InstanceState

如果没有配置映射,则会引发sqlalchemy.orm.exc.UnmappedInstanceError

通过 inspect() 函数可以获得等效功能,如下所示:

inspect(instance)

使用检查系统将会在实例不属于映射的情况下引发sqlalchemy.exc.NoInspectionAvailable

function sqlalchemy.orm.attributes.del_attribute(instance: object, key: str) → None

删除属性的值,触发历史事件。

无论直接应用于类的工具化如何,都可以使用此函数,即不需要描述符。自定义属性管理方案将需要使用此方法来建立由 SQLAlchemy 理解的属性状态。

function sqlalchemy.orm.attributes.get_attribute(instance: object, key: str) → Any

获取属性的值,触发任何所需的可调用对象。

无论直接应用于类的仪器是什么,都可以使用此函数,即不需要描述符。自定义属性管理方案将需要使用此方法来使用 SQLAlchemy 理解的属性状态。

function sqlalchemy.orm.attributes.get_history(obj: object, key: str, passive: PassiveFlag = symbol('PASSIVE_OFF')) → History

返回给定对象和属性键的History记录。

这是给定属性的预刷新历史记录,每次Session刷新对当前数据库事务进行更改时都会重置。

注意

优先使用AttributeState.historyAttributeState.load_history()访问器来检索实例属性的History

参数:

  • obj - 其类由属性包装的对象。

  • key - 字符串属性名称。

  • passive - 如果值尚不存在,则指示属性的加载行为。这是一个比特标志属性,默认为符号PASSIVE_OFF,表示应发出所有必要的 SQL。

另请参阅

AttributeState.history

AttributeState.load_history() - 如果值未在本地存在,则使用加载器可调用检索历史记录。

function sqlalchemy.orm.attributes.init_collection(obj: object, key: str) → CollectionAdapter

初始化集合属性并返回集合适配器。

此函数用于为先前未加载的属性提供直接访问集合内部。例如:

collection_adapter = init_collection(someobject, 'elements')
for elem in values:
    collection_adapter.append_without_event(elem)

要更轻松地执行上述操作,请参见set_committed_value()

参数:

  • obj - 一个映射对象

  • key - 集合所在的字符串属性名称。

function sqlalchemy.orm.attributes.flag_modified(instance: object, key: str) → None

将实例上的属性标记为“修改”。

这将在实例上设置“修改”标志,并为给定属性建立一个无条件的更改事件。属性必须有一个值存在,否则会引发InvalidRequestError

要将对象标记为“脏”,而不引用任何特定属性,以便在刷新时将其视为“脏”,请使用flag_dirty()调用。

另请参阅

flag_dirty()

function sqlalchemy.orm.attributes.flag_dirty(instance: object) → None

将实例标记为“脏”,而不提及任何特定属性。

这是一个特殊操作,将允许对象通过刷新过程,以便被SessionEvents.before_flush()等事件拦截。请注意,对于没有更改的对象,在刷新过程中不会发出任何 SQL,即使通过此方法标记为脏。但是,SessionEvents.before_flush()处理程序将能够在Session.dirty集合中看到对象,并可能对其进行更改,然后将其包含在发出的 SQL 中。

版本 1.2 中的新功能。

另请参阅

flag_modified()

function sqlalchemy.orm.attributes.instance_state()

返回给定映射对象的InstanceState

此函数是object_state()的内部版本。在这里,建议使用object_state()和/或inspect()函数,因为它们会在给定对象未映射时分别发出信息性异常。

function sqlalchemy.orm.instrumentation.is_instrumented(instance, key)

如果给定实例上的给定属性由属性包进行了仪器化,则返回 True。

无论直接应用于类的仪器化如何,都可以使用此函数,即不需要描述符。

function sqlalchemy.orm.attributes.set_attribute(instance: object, key: str, value: Any, initiator: AttributeEventToken | None = None) → None

设置属性的值,触发历史事件。

无论直接应用于类的仪器化如何,都可以使用此函数,即不需要描述符。自定义属性管理方案将需要使用此方法来建立 SQLAlchemy 理解的属性状态。

参数:

  • instance – 将被修改的对象

  • key – 属性的字符串名称

  • value – 要分配的值

  • initiator

    一个Event的实例,可能已从先前的事件侦听器传播。当在现有事件侦听函数中使用set_attribute()函数时,会使用此参数;该对象可用于跟踪事件链的起源。

    版本 1.2.3 中的新功能。

function sqlalchemy.orm.attributes.set_committed_value(instance, key, value)

设置没有历史事件的属性的值。

取消任何先前存在的历史。对于持有标量属性的属性,值应为标量值,对于任何持有集合属性的属性,值应为可迭代对象。

当惰性加载程序触发并从数据库加载附加数据时,使用的是相同的基础方法。特别是,此方法可被应用代码使用,通过单独的查询加载了额外的属性或集合,然后将其附加到实例,就好像它是其原始加载状态的一部分。

class sqlalchemy.orm.attributes.History

一个由添加、未更改和删除值组成的 3 元组,表示在受监控属性上发生的更改。

获取对象上特定属性的History对象的最简单方法是使用inspect()函数:

from sqlalchemy import inspect

hist = inspect(myobject).attrs.myattribute.history

每个元组成员都是一个可迭代序列:

  • added - 添加到属性中的项目集合(第一个元组元素)。

  • unchanged - 未更改属性上的项目集合(第二个元组元素)。

  • deleted - 从属性中删除的项目集合(第三个元组元素)。

成员

added, deleted, empty(), has_changes(), non_added(), non_deleted(), sum(), unchanged

类签名

sqlalchemy.orm.Historybuiltins.tuple

attribute added: Tuple[()] | List[Any]

字段 0 的别名

attribute deleted: Tuple[()] | List[Any]

字段 2 的别名

method empty() → bool

如果此History没有更改和现有的未更改状态,则返回 True。

method has_changes() → bool

如果此History有更改,则返回 True。

method non_added() → Sequence[Any]

返回一个未更改+删除的集合。

method non_deleted() → Sequence[Any]

返回一个添加+未更改的集合。

method sum() → Sequence[Any]

返回一个添加+未更改+删除的集合。

attribute unchanged: Tuple[()] | List[Any]

字段 1 的别名

Session 和 sessionmaker()

对象名称 描述
ORMExecuteState 表示对Session.execute()方法的调用,作为传递给SessionEvents.do_orm_execute()事件钩子。
Session 管理 ORM 映射对象的持久性操作。
sessionmaker 一个可配置的Session工厂。
SessionTransaction 一个Session级事务。
SessionTransactionOrigin 表示SessionTransaction的来源。
class sqlalchemy.orm.sessionmaker

可配置的Session工厂。

当调用sessionmaker工厂时,会根据此处设定的配置参数生成新的Session对象。

例如:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# an Engine, which the Session will use for connection
# resources
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')

Session = sessionmaker(engine)

with Session() as session:
    session.add(some_object)
    session.add(some_other_object)
    session.commit()

上下文管理器的使用是可选的;否则,返回的Session对象可以通过Session.close()方法显式关闭。使用try:/finally:块是可选的,但是会确保即使出现数据库错误也会执行关闭操作:

session = Session()
try:
    session.add(some_object)
    session.add(some_other_object)
    session.commit()
finally:
    session.close()

sessionmaker的作用类似于EngineConnection对象的工厂。通过这种方式,它还包括一个sessionmaker.begin()方法,提供一个上下文管理器,既开始又提交事务,并在完成时关闭Session,如果发生任何错误则回滚事务:

Session = sessionmaker(engine)

with Session.begin() as session:
    session.add(some_object)
    session.add(some_other_object)
# commits transaction, closes session

1.4 版本中新增。

当调用sessionmaker构造Session时,也可以传递关键字参数给该方法;这些参数将覆盖全局配置的参数。下面我们使用一个绑定到特定Enginesessionmaker来生成一个与该引擎提供的特定Connection绑定的Session

Session = sessionmaker(engine)

# bind an individual session to a connection

with engine.connect() as connection:
    with Session(bind=connection) as session:
        # work with session

该类还包括一个sessionmaker.configure() 方法,该方法可用于指定工厂的额外关键字参数,这些参数将对后续生成的Session 对象生效。通常用于在首次使用之前将一个或多个Engine 对象与现有的sessionmaker 工厂关联起来:

# application starts, sessionmaker does not have
# an engine bound yet
Session = sessionmaker()

# ... later, when an engine URL is read from a configuration
# file or other events allow the engine to be created
engine = create_engine('sqlite:///foo.db')
Session.configure(bind=engine)

sess = Session()
# work with session

另请参阅

打开和关闭会话 - 使用sessionmaker 创建会话的简介文本。

成员

call(), init(), begin(), close_all(), configure(), identity_key(), object_session()

类签名

sqlalchemy.orm.sessionmaker (sqlalchemy.orm.session._SessionClassMethods, typing.Generic)

method __call__(**local_kw: Any) → _S

使用此sessionmaker 中建立的配置生成新的Session 对象。

在 Python 中,当对象“调用”方式与函数相同时,将调用对象上的__call__方法:

Session = sessionmaker(some_engine)
session = Session()  # invokes sessionmaker.__call__()
method __init__(bind: Optional[_SessionBind] = None, *, class_: Type[_S] = <class 'sqlalchemy.orm.session.Session'>, autoflush: bool = True, expire_on_commit: bool = True, info: Optional[_InfoType] = None, **kw: Any)

构造一个新的sessionmaker

这里的所有参数,除了class_,都对应于直接由Session 接受的参数。有关参数的更多详细信息,请参阅Session.__init__() 文档字符串。

参数:

  • bind – 与新创建的Session 对象关联的Engine 或其他 Connectable

  • class_ – 用于创建新的Session 对象的类。默认为Session

  • autoflush

    与新创建的Session 对象一起使用的自动刷新设置。

    另请参阅

    刷新 - 关于自动刷新的额外背景信息

  • expire_on_commit=True – 与新创建的Session 对象一起使用的Session.expire_on_commit 设置。

  • info – 可选字典,可以通过Session.info访问。请注意,当info参数被指定给特定的Session构造操作时,此字典会被更新而不是被替换。

  • **kw – 所有其他关键字参数都将传递给新创建的Session对象的构造函数。

method begin() → AbstractContextManager[_S]

生成一个上下文管理器,既提供一个新的Session又提供一个提交的事务。

例如:

Session = sessionmaker(some_engine)

with Session.begin() as session:
    session.add(some_object)

# commits transaction, closes session

自版本 1.4 起新增。

classmethod close_all() → None

继承自 sqlalchemy.orm.session._SessionClassMethods.close_all 方法的 sqlalchemy.orm.session._SessionClassMethods

关闭所有内存中的会话。

自版本 1.3 起弃用:Session.close_all()方法已弃用,将在将来的版本中删除。请参考close_all_sessions()

method configure(**new_kw: Any) → None

(重新)配置此 sessionmaker 的参数。

例如:

Session = sessionmaker()

Session.configure(bind=create_engine('sqlite://'))
classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

继承自 sqlalchemy.orm.session._SessionClassMethods.identity_key 方法的 sqlalchemy.orm.session._SessionClassMethods

返回一个标识键。

这是identity_key()的别名。

classmethod object_session(instance: object) → Session | None

继承自 sqlalchemy.orm.session._SessionClassMethods.object_session 方法的 sqlalchemy.orm.session._SessionClassMethods

返回对象所属的Session

这是object_session()的别名。

class sqlalchemy.orm.ORMExecuteState

表示对Session.execute()方法的调用,如传递给SessionEvents.do_orm_execute()事件挂钩。

自版本 1.4 起新增。

另请参见

执行事件 - 如何使用SessionEvents.do_orm_execute()的顶级文档

成员

init(), all_mappers, bind_arguments, bind_mapper, execution_options, invoke_statement(), is_column_load, is_delete, is_executemany, is_from_statement, is_insert, is_orm_statement, is_relationship_load, is_select, is_update, lazy_loaded_from, load_options, loader_strategy_path, local_execution_options, parameters, session, statement, update_delete_options, update_execution_options(), user_defined_options

类签名

sqlalchemy.orm.ORMExecuteState (sqlalchemy.util.langhelpers.MemoizedSlots)

method __init__(session: Session, statement: Executable, parameters: _CoreAnyExecuteParams | None, execution_options: _ExecuteOptions, bind_arguments: _BindArguments, compile_state_cls: Type[ORMCompileState] | None, events_todo: List[_InstanceLevelDispatch[Session]])

构造一个新的ORMExecuteState

此对象在内部构造。

attribute all_mappers

返回一个包含此语句顶层涉及的所有Mapper对象的序列。

所谓“顶层”是指那些在select()查询的结果集行中表示的Mapper对象,或者对于update()delete()查询,即 UPDATE 或 DELETE 的主要主题的映射器。

版本 1.4.0b2 中的新内容。

另请参阅

ORMExecuteState.bind_mapper

attribute bind_arguments: _BindArguments

作为Session.execute.bind_arguments字典传递的字典。

此字典可供Session的扩展使用,以传递将帮助确定在一组数据库连接中应使用哪一个来调用此语句的参数。

attribute bind_mapper

返回主要的“bind”映射器Mapper

对于调用 ORM 语句的ORMExecuteState对象,即ORMExecuteState.is_orm_statement属性为True,此属性将返回被认为是语句的“主要”映射器的Mapper。术语“bind mapper”指的是Session对象可能被“绑定”到多个映射类键到映射类的多个Engine对象,并且“bind mapper”确定哪些Engine对象将被选择。

对于针对单个映射类调用的语句,ORMExecuteState.bind_mapper 旨在是一种可靠的方式来获取此映射器。

版本 1.4.0b2 中的新功能。

另请参阅

ORMExecuteState.all_mappers

attribute execution_options: _ExecuteOptions

当前执行选项的完整字典。

这是语句级选项与本地传递的执行选项的合并。

另请参阅

ORMExecuteState.local_execution_options

Executable.execution_options()

ORM 执行选项

method invoke_statement(statement: Executable | None = None, params: _CoreAnyExecuteParams | None = None, execution_options: OrmExecuteOptionsParameter | None = None, bind_arguments: _BindArguments | None = None) → Result[Any]

执行由此ORMExecuteState表示的语句,而不重新调用已经进行的事件。

该方法实质上执行当前语句的可重入执行,当前正在调用SessionEvents.do_orm_execute()事件。这样做的用例是为了事件处理程序想要覆盖最终Result对象返回方式,比如从离线缓存中检索结果或者从多次执行中连接结果的方案。

当实际处理程序函数在SessionEvents.do_orm_execute()中返回Result对象,并传播到调用的Session.execute()方法时,Session.execute()方法的其余部分被抢占,Result对象立即返回给Session.execute()的调用者。

参数:

  • statement – 可选的要调用的语句,代替当前由ORMExecuteState.statement表示的语句。

  • params

    可选的参数字典或参数列表,将合并到此ORMExecuteState的现有ORMExecuteState.parameters中。

    从版本 2.0 开始更改:接受参数字典列表进行 executemany 执行。

  • execution_options – 可选的执行选项字典将合并到此ORMExecuteState的现有ORMExecuteState.execution_options中。

  • bind_arguments – 可选的绑定参数字典,将在此ORMExecuteState的当前ORMExecuteState.bind_arguments中合并。

返回值:

一个带有 ORM 级别结果的Result对象。

另请参阅

重新执行语句 - 关于适当使用 ORMExecuteState.invoke_statement() 的背景和示例。

attribute is_column_load

如果操作是刷新现有 ORM 对象上的面向列的属性,则返回 True。

在诸如 Session.refresh() 之类的操作期间发生,以及在加载由 defer() 推迟的属性时,或者正在加载已由 Session.expire() 直接或通过提交操作过期的属性时。

当发生此类操作时,处理程序很可能不希望向查询添加任何选项,因为查询应该是一个直接的主键获取,不应该有任何额外的 WHERE 条件,并且随实例传递的加载器选项已经添加到查询中。

新版本 1.4.0b2 中新增。

另请参阅

ORMExecuteState.is_relationship_load

attribute is_delete

如果这是一个 DELETE 操作,则返回 True。

在版本 2.0.30 中更改:- 该属性对于自身针对 Delete 构造的 Select.from_statement() 构造也为 True,例如 select(Entity).from_statement(delete(..))

attribute is_executemany

如果参数是一个多元素字典列表,并且有多个字典,则返回 True。

新版本 2.0 中新增。

attribute is_from_statement

��果这是一个 Select.from_statement() 操作,则返回 True。

这与 ORMExecuteState.is_select 独立,因为 select().from_statement() 构造也可以与 INSERT/UPDATE/DELETE RETURNING 类型的语句一起使用。只有在 Select.from_statement() 本身针对 Select 构造时,才会设置 ORMExecuteState.is_select

新版本 2.0.30 中新增。

attribute is_insert

如果这是一个 INSERT 操作,则返回 True。

在版本 2.0.30 中更改:- 对于Select.from_statement()构造本身针对Insert构造,例如select(Entity).from_statement(insert(..)),该属性也为 True

attribute is_orm_statement

如果操作是 ORM 语句,则返回 True。

这表明调用 select()、insert()、update()或 delete()包含 ORM 实体作为主题。对于不包含 ORM 实体而仅引用Table元数据的语句,它被调用为核心 SQL 语句,并且不会发生 ORM 级别的自动化。

attribute is_relationship_load

如果此加载正在代表关系加载对象,则返回 True。

这意味着,实际上加载程序是一个 LazyLoader、SelectInLoader、SubqueryLoader 或类似的加载程序,并且整个 SELECT 语句是代表一个关系加载发出的。

当发生此类操作时,处理程序很可能不希望向查询添加任何选项,因为加载程序选项已经能够传播到关系加载程序并且应该已经存在。

另请参阅

ORMExecuteState.is_column_load

attribute is_select

如果这是一个选择操作,则返回 True。

在版本 2.0.30 中更改:- 对于Select.from_statement()构造本身针对Select构造,例如select(Entity).from_statement(select(..)),该属性也为 True

attribute is_update

如果这是一个更新操作,则返回 True。

在版本 2.0.30 中更改:- 对于Select.from_statement()构造本身针对Update构造,例如select(Entity).from_statement(update(..)),该属性也为 True

attribute lazy_loaded_from

使用此语句执行进行惰性加载操作的InstanceState

此属性的主要原因是支持水平分片扩展,该扩展在此扩展创建的特定查询执行时间挂钩中可用。为此,该属性仅打算在查询执行时间有意义,并且重要的是不包括任何之前的时间,包括查询编译时间。

attribute load_options

返回将用于此执行的 load_options。

attribute loader_strategy_path

返回当前加载路径的PathRegistry

此对象表示在查询中沿着关系的“路径”时,加载特定对象或集合的情况。

attribute local_execution_options: _ExecuteOptions

传递给Session.execute()方法的执行选项的字典视图。

此处不包括与所调用语句相关的选项。

另请参阅

ORMExecuteState.execution_options

attribute parameters: _CoreAnyExecuteParams | None

传递给Session.execute()的参数字典。

attribute session: Session

正在使用的Session

attribute statement: Executable

所调用的 SQL 语句。

对于从Query检索的 ORM 选择,这是从 ORM 查询生成的select的一个实例。

attribute update_delete_options

返回将用于此执行的 update_delete_options。

method update_execution_options(**opts: Any) → None

使用新值更新本地执行选项。

attribute user_defined_options

已与所调用语句相关联的UserDefinedOptions序列。

class sqlalchemy.orm.Session

管理 ORM 映射对象的持久性操作。

Session不适合在并发线程中使用。请参阅 Session 线程安全吗?AsyncSession 在并发任务中安全共享吗?了解背景信息。

关于 Session 的使用范例,请参阅使用 Session。

成员

init(), add(), add_all(), begin(), begin_nested(), bind_mapper(), bind_table(), bulk_insert_mappings(), bulk_save_objects(), bulk_update_mappings(), close(), close_all(), commit(), connection(), delete(), deleted, dirty, enable_relationship_loading(), execute(), expire(), expire_all(), expunge(), expunge_all(), flush(), get(), get_bind(), get_nested_transaction(), get_one(), get_transaction(), identity_key(), identity_map, in_nested_transaction(), in_transaction(), info, invalidate(), is_active, is_modified(), merge(), new, no_autoflush, object_session(), prepare(), query(), refresh(), reset(), rollback(), scalar(), scalars()

类签名

sqlalchemy.orm.Session (sqlalchemy.orm.session._SessionClassMethods, sqlalchemy.event.registry.EventTarget)

method __init__(bind: _SessionBind | None = None, *, autoflush: bool = True, future: Literal[True] = True, expire_on_commit: bool = True, autobegin: bool = True, twophase: bool = False, binds: Dict[_SessionBindKey, _SessionBind] | None = None, enable_baked_queries: bool = True, info: _InfoType | None = None, query_cls: Type[Query[Any]] | None = None, autocommit: Literal[False] = False, join_transaction_mode: JoinTransactionMode = 'conditional_savepoint', close_resets_only: bool | _NoArg = _NoArg.NO_ARG)

构造一个新的Session

请参见sessionmaker函数,该函数用于生成带有给定参数集的Session产生的可调用对象。

参数:

  • autoflush

    当为True时,所有查询操作将在继续之前对此Session执行Session.flush()调用。这是一个方便的特性,使得不需要反复调用Session.flush()以便数据库查询检索结果。

    请参见

    刷新 - 关于自动刷新的额外背景信息

  • autobegin

    在请求操作时自动启动事务(即等同于调用Session.begin()) 。默认为True。设置为False以防止Session在构造之后以及在调用任何 Session.rollback()Session.commit()Session.close() 方法之后隐式开始事务。

    从 2.0 版本开始新增。

    请参见

    禁用 Autobegin 以防止隐式事务

  • bind – 可选的EngineConnection,应该绑定到此Session。指定时,此会话执行的所有 SQL 操作将通过此可连接对象执行。

  • binds

    一个字典,可能指定任意数量的EngineConnection对象作为 SQL 操作的连接源,以实体为单位。字典的键由任何一系列映射类、任意 Python 类(作为映射类的基类)、Table对象和Mapper对象组成。然后,字典的值是Engine的实例,或者较少见的是Connection对象。针对特定映射类进行的操作将查阅此字典,以确定哪个Engine应该用于特定的 SQL 操作。解析的完整启发式描述在Session.get_bind()中。用法示例如下:

    Session = sessionmaker(binds={
        SomeMappedClass: create_engine('postgresql+psycopg2://engine1'),
        SomeDeclarativeBase: create_engine('postgresql+psycopg2://engine2'),
        some_mapper: create_engine('postgresql+psycopg2://engine3'),
        some_table: create_engine('postgresql+psycopg2://engine4'),
        })
    

    另请参见

    分区策略(例如,每个会话多个数据库后端)

    Session.bind_mapper()

    Session.bind_table()

    Session.get_bind()

  • class_ – 指定除了 sqlalchemy.orm.session.Session 外应该由返回的类使用的替代类。这是唯一作为 sessionmaker 函数本地的参数,并且不直接发送到 Session 的构造函数。

  • enable_baked_queries

    遗留;默认为 True。由 sqlalchemy.ext.baked 扩展使用的参数,用于确定是否应缓存“烘焙查询”,如此扩展的正常操作所用。当设置为 False 时,此特定扩展使用的缓存被禁用。

    从版本 1.4 起更改:sqlalchemy.ext.baked 扩展是遗留的,并且没有被 SQLAlchemy 的任何内部使用。因此,此标志仅影响明确在其自己的代码中使用此扩展的应用程序。

  • expire_on_commit

    默认为 True。当为 True 时,每次 commit() 后所有实例都将完全过期,以便在完成事务后的所有属性/对象访问加载最新的数据库状态。

    另请参见

    提交

  • future

    已弃用;此标志始终为 True。

    另请参见

    SQLAlchemy 2.0 - 主要迁移指南

  • info – 可选字典,与此 Session 关联的任意数据。可通过 Session.info 属性访问。请注意,字典在构造时被复制,因此对每个 Session 字典的修改将局限于该 Session

  • query_cls – 应该用于创建新的查询对象的类,由 Session.query() 方法返回。默认为 Query

  • twophase – 当设置为True时,所有事务都将作为“两阶段”事务启动,即使用正在使用的数据库的“两阶段”语义以及一个 XID。在commit()之后,对所有已附加数据库发出flush()后,将调用每个数据库的TwoPhaseTransaction.prepare()方法的TwoPhaseTransaction。这允许每个数据库在提交每个事务之前回滚整个事务。

  • autocommitautocommit关键字出现是为了向后兼容,但必须保持其默认值为False

  • join_transaction_mode

    描述了在给定绑定是Session之外已经开始事务的Connection时应采取的事务行为;换句话说,Connection.in_transaction()方法返回 True。

    以下行为仅在Session 实际使用给定的连接时才生效;也就是说,诸如Session.execute()Session.connection()等方法实际上被调用:

    • "conditional_savepoint" - 这是默认行为。如果给定的Connection在事务中开始但没有 SAVEPOINT,则使用"rollback_only"。如果Connection此外还在 SAVEPOINT 中,换句话说,Connection.in_nested_transaction()方法返回 True,则使用"create_savepoint"

      "conditional_savepoint" 行为试图利用保存点来保持现有事务的状态不变,但仅在已经存在保存点的情况下;否则,不假设所使用的后端具有足够的 SAVEPOINT 支持,因为该功能的可用性有所不同。 "conditional_savepoint" 还试图与先前 Session 行为建立大致的向后兼容性,用于未设置特定模式的应用程序。建议使用其中一个明确的设置。

    • "create_savepoint" - Session 将在所有情况下使用 Connection.begin_nested() 来创建自己的事务。这个事务本质上是“在顶部”的任何存在的事务之上打开的;如果底层数据库和正在使用的驱动程序完全支持 SAVEPOINT,那么外部事务将在 Session 生命周期内保持不受影响。

      "create_savepoint" 模式对于将 Session 集成到测试套件中并保持外部启动的事务不受影响最为有用;然而,它依赖于底层驱动程序和数据库的正确 SAVEPOINT 支持。

      提示

      使用 SQLite 时,Python 3.11 中包含的 SQLite 驱动在某些情况下不能正确处理 SAVEPOINTs,需要通过一些变通方法。请参阅 Serializable isolation / Savepoints / Transactional DDL 和 Serializable isolation / Savepoints / Transactional DDL(asyncio 版本)部分,了解当前的解决方法详情。

    • "control_fully" - Session 将接管给定的事务作为自己的事务;Session.commit() 将在事务上调用 .commit()Session.rollback() 将在事务上调用 .rollback()Session.close() 将调用事务的 .rollback

      提示

      此使用模式相当于 SQLAlchemy 1.4 如何处理具有现有 SAVEPOINT 的Connection(即Connection.begin_nested()); Session将完全控制现有 SAVEPOINT。

    • "rollback_only" - Session将仅控制给定事务进行.rollback()调用;.commit()调用不会传播到给定事务。.close()调用对给定事务没有影响。

      提示

      此使用模式相当于 SQLAlchemy 1.4 如何处理具有现有常规数据库事务的Connection(即Connection.begin()); Session将传播Session.rollback()调用到底层事务,但不会传播Session.commit()Session.close()调用。

    在版本 2.0.0rc1 中新增。

  • close_resets_only

    默认为True。确定在调用.close()后会话是否应重置自身,或者应传入不再可用的状态,禁用重用。

    新版本 2.0.22 中新增标志close_resets_only。将来的 SQLAlchemy 版本可能会将此标志的默认值更改为False

    另请参阅

    关闭 - 有关Session.close()Session.reset()语义的详细信息。

method add(instance: object, _warn: bool = True) → None

将对象放入此Session

当传递给Session.add()方法时处于瞬态状态的对象将转移到挂起状态,直到下一次刷新,然后它们将转移到持久化状态。

当传递给Session.add()方法时处于分离状态的对象将直接转移到持久化状态。

如果Session使用的事务被回滚,则在传递给Session.add()时是瞬时的对象将被移回瞬时状态,并且将不再存在于此Session中。

另请参见

Session.add_all()

添加新项目或现有项目 - 在使用会话的基础知识中

method add_all(instances: Iterable[object]) → None

将给定的实例集合添加到此Session中。

请参阅Session.add()的文档以获取一般行为描述。

另请参见

Session.add()

添加新项目或现有项目 - 在使用会话的基础知识中

method begin(nested: bool = False) → SessionTransaction

在此Session上开始事务或嵌套事务(如果尚未开始)。

Session对象具有自动开始行为,因此通常不需要显式调用Session.begin()方法。但是,可以用来控制事务状态开始的范围。

当用于开始最外层事务时,如果此Session已经在事务中,则会引发错误。

参数:

嵌套 - 如果为 True,则开始一个 SAVEPOINT 事务,等效于调用Session.begin_nested()。有关 SAVEPOINT 事务的文档,请参见使用 SAVEPOINT。

返回:

SessionTransaction对象。请注意,SessionTransaction充当 Python 上下文管理器,允许在“with”块中使用Session.begin()。请参见显式开始以获取示例。

另请参见

自动开始

管理事务

Session.begin_nested()

method begin_nested() → SessionTransaction

在此会话上开始“嵌套”事务,例如 SAVEPOINT。

目标数据库和相关驱动程序必须支持 SQL SAVEPOINT 才能使此方法正常运行。

有关 SAVEPOINT 事务的文档,请参阅使用 SAVEPOINT。

返回:

SessionTransaction对象。请注意,SessionTransaction作为上下文管理器,允许在“with”块中使用Session.begin_nested()。请参阅使用 SAVEPOINT 获取用法示例。

另请参阅

使用 SAVEPOINT

可序列化隔离/保存点/事务性 DDL - 针对 SQLite 驱动程序需要特殊的解决方案,以使 SAVEPOINT 正常工作。对于 asyncio 用例,请参阅可序列化隔离/保存点/事务性 DDL(asyncio 版本)部分。

method bind_mapper(mapper: _EntityBindKey[_O], bind: _SessionBind) → None

Mapper或任意 Python 类与“bind”相关联,例如EngineConnection

给定的实体被添加到Session.get_bind()方法使用的查找中。

参数:

  • mapper – 一个Mapper对象,或者是一个映射类的实例,或者是任何作为一组映射类基类的 Python 类。

  • bind – 一个EngineConnection对象。

另请参阅

分区策略(例如每个会话多个数据库后端)

Session.binds

Session.bind_table()

method bind_table(table: TableClause, bind: Engine | Connection) → None

Table与“bind”相关联,例如EngineConnection

给定的Table被添加到Session.get_bind()方法使用的查找中。

参数:

  • table – 一个Table对象,通常是 ORM 映射的目标,或者存在于被映射的可选择性内。

  • bind – 一个EngineConnection对象。

另请参阅

分区策略(例如每个 Session 多个数据库后端)

Session.binds

Session.bind_mapper()

method bulk_insert_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]], return_defaults: bool = False, render_nulls: bool = False) → None

对给定的映射字典列表执行批量插入。

旧特性

该方法是 SQLAlchemy 2.0 系列的旧特性。对于现代的批量 INSERT 和 UPDATE,请参阅 ORM 批量 INSERT 语句和 ORM 按主键批量 UPDATE 部分。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:

  • mapper – 一个映射类,或者实际的Mapper对象,表示映射列表中表示的单一对象类型。

  • mappings – 一个字典序列,每个字典包含要插入的映射行的状态,以映射类上的属性名称为准。如果映射涉及多个表,比如联合继承映射,每个字典必须包含要填充到所有表中的所有键。

  • return_defaults

    当为 True 时,INSERT 过程将被修改以确保新生成的主键值将被获取。通常此参数的理由是为了使联合表继承映射能够进行批量插入。

    注意

    对于不支持 RETURNING 的后端,Session.bulk_insert_mappings.return_defaults参数可以显著降低性能,因为 INSERT 语句不能再批量处理。请参阅“插入多个值”行为对 INSERT 语句的影响以了解哪些后端受到影响。

  • render_nulls

    当为 True 时,None值将导致在 INSERT 语句中包含一个 NULL 值,而不是将列从 INSERT 中省略。这允许所有被 INSERT 的行具有相同的列集,从而允许将完整的行集批量发送到 DBAPI。通常,每个包含与前一行不同的 NULL 值组合的列集必须从渲染的 INSERT 语句中省略不同的列系列,这意味着必须将其作为单独的语句发出。通过传递此标志,可以确保将完整的行集批量处理为一个批次;但成本是,通过省略的列调用的服务器端默认值将被跳过,因此必须确保这些不是必需的。

    警告

    当设置了此标志时,服务器端默认的 SQL 值不会被调用,对于那些以 NULL 插入的列;NULL 值将被显式发送。必须确保整个操作不需要调用任何服务器端默认函数。

另请参阅

启用 ORM 的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_save_objects()

Session.bulk_update_mappings()

method bulk_save_objects(objects: Iterable[object], return_defaults: bool = False, update_changed_only: bool = True, preserve_order: bool = True) → None

对给定对象列表执行批量保存。

旧特性

该方法是 SQLAlchemy 2.0 系列的一个旧特性。对于现代的批量 INSERT 和 UPDATE,请参阅 ORM 批量 INSERT 语句和按主键批量 UPDATE 部分。

对于一般的 INSERT 和更新现有 ORM 映射对象,建议使用标准的工作单元数据管理模式,介绍在 SQLAlchemy 统一教程中的 ORM 数据操作。SQLAlchemy 2.0 现在使用现代方言的“插入多个值”行为用于 INSERT 语句,解决了以前批量 INSERT 速度慢的问题。

参数:

  • objects

    一系列映射对象实例。映射对象将按原样持久化,并且之后Session关联。

    对于每个对象,对象是作为 INSERT 还是 UPDATE 发送取决于Session在传统操作中使用的相同规则;如果对象具有InstanceState.key属性设置,则假定对象是“分离的”并将导致 UPDATE。否则,将使用 INSERT。

    在 UPDATE 的情况下,根据哪些属性已更改,语句将被分组,因此将成为每个 SET 子句的主题。如果update_changed_only为 False,则将每个对象中存在的所有属性应用于 UPDATE 语句,这可能有助于将语句组合成更大的 executemany(),并且还将减少检查属性历史记录的开销。

  • return_defaults – 当为 True 时,缺少生成默认值的值的行,即整数主键默认值和序列,将逐个插入,以便主键值可用。特别是,这将允许联合继承和其他多表映射正确插入,而无需提前提供主键值;但是,Session.bulk_save_objects.return_defaults 极大地降低了方法的性能收益。强烈建议使用标准的Session.add_all()方法。

  • update_changed_only – 当为 True 时,根据每个状态中记录的更改的属性生成 UPDATE 语句。当为 False 时,除了主键属性之外,所有存在的属性都将生成到 SET 子句中。

  • preserve_order – 当为 True 时,插入和更新的顺序与给定对象的顺序完全匹配。当为 False 时,常见类型的对象将分组为插入和更新,以允许更多的批处理机会。

另请参阅

ORM 启用的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_update_mappings()

method bulk_update_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]) → None

对给定的映射字典列表执行批量更新。

遗留特性

该方法是 SQLAlchemy 2.0 系列的遗留特性。有关现代批量 INSERT 和 UPDATE,请参见 ORM 批量 INSERT 语句和 ORM 按主键批量 UPDATE 章节。2.0 API 与该方法共享实现细节,并添加了新功能。

参数:

  • mapper – 映射类,或者表示映射列表中所表示的单个对象的实际Mapper对象。

  • mappings - 一个字典序列,每个字典包含要更新的映射行的状态,以映射类上的属性名称表示。如果映射涉及多个表,例如连接继承映射,每个字典可能包含与所有表对应的键。所有那些存在且不是主键的键将应用于 UPDATE 语句的 SET 子句;必需的主键值将应用于 WHERE 子句。

另请参阅

启用 ORM 的 INSERT、UPDATE 和 DELETE 语句

Session.bulk_insert_mappings()

Session.bulk_save_objects()

method close() → None

关闭此Session使用的事务资源和 ORM 对象。

这将清除与此Session关联的所有 ORM 对象,结束任何正在进行的事务,并释放此Session自身从关联的Engine对象中签出的任何Connection对象。然后,该操作将使Session处于可以再次使用的状态。

提示

在默认运行模式下,Session.close()方法不会阻止再次使用 SessionSession本身实际上没有明确的“关闭”状态;它仅意味着Session将释放所有数据库连接和 ORM 对象。

将参数Session.close_resets_only设置为False将使close变为最终状态,这意味着对会话的任何进一步操作都将被禁止。

从版本 1.4 开始更改:Session.close()方法不会立即创建新的SessionTransaction对象;相反,只有在再次为数据库操作使用Session时才会创建新的SessionTransaction

另请参阅

关闭会话 - 关于Session.close()Session.reset()语义的详细信息。

Session.reset() - 与参数Session.close_resets_only设置为Trueclose()类似的方法。

classmethod close_all() → None

sqlalchemy.orm.session._SessionClassMethods.close_all 方法继承

关闭内存中的所有会话。

从版本 1.3 开始已废弃:Session.close_all() 方法已被废弃,并将在将来的版本中删除。请参考 close_all_sessions()

method commit() → None

刷新待定更改并提交当前事务。

当 COMMIT 操作完成时,所有对象都将被完全过期,擦除其内部内容,下次访问这些对象时将自动重新加载。在此期间,这些对象处于过期状态,如果从Session中分离,则无法正常使用。此外,在使用基于 asyncio 的 API 时不支持此重新加载操作。可以使用Session.expire_on_commit参数来禁用此行为。

Session中没有事务时,表示自上次调用Session.commit()以来没有在此Session上调用任何操作,则该方法将开始并提交一个仅内部使用的“逻辑”事务,通常不会影响数据库,除非检测到待定刷新更改,但仍会调用事件处理程序和对象过期规则。

最外层的数据库事务会无条件提交,自动释放任何当前有效的 SAVEPOINT。

另请参阅

提交

事务管理

在使用 AsyncSession 时避免隐式 IO

method connection(bind_arguments: _BindArguments | None = None, execution_options: CoreExecuteOptionsParameter | None = None) → Connection

返回与此Session对象的事务状态对应的Connection对象。

返回与当前事务对应的Connection,或者如果没有进行中的事务,则开始一个新事务并返回Connection(请注意,在发出第一条 SQL 语句之前,不会与 DBAPI 建立事务状态)。

多绑定或未绑定的Session对象中的歧义可以通过任何可选关键字参数解决。最终,使用get_bind()方法进行解析。

参数:

  • bind_arguments – 绑定参数字典。可能包括“mapper”、“bind”、“clause”等传递给Session.get_bind()的其他自定义参数。

  • execution_options

    一个执行选项字典,将仅在首次获取连接时传递给Connection.execution_options()。如果连接已经存在于Session中,则会发出警告并忽略参数。

    另请参见

    设置事务隔离级别 / DBAPI AUTOCOMMIT

method delete(instance: object) → None

将实例标记为已删除。

假定传递的对象在调用方法后将保持在 persistent 或 detached 状态;在下次刷新之前,对象将保持在 persistent 状态。在此期间,对象还将是Session.deleted集合的成员。

下次刷新时,对象将转移到 deleted 状态,表示在当前事务中为其行发出了DELETE语句。当事务成功提交时,已删除的对象将移至 detached 状态,并不再存在于此Session中。

另请参见

删除 - 在使用会话的基础知识

attribute deleted

在此Session中标记为‘deleted’的所有实例的集合

attribute dirty

所有被视为脏数据的持久实例的集合。

例如:

some_mapped_object in session.dirty

当实例被修改但未被删除时,被视为脏数据。

请注意,这种‘脏’计算是‘乐观的’;大多数属性设置或集合修改操作都会将实例标记为‘脏’并将其放入此集合中,即使属性的值没有净变化也是如此。在刷新时,将每个属性的值与其先前保存的值进行比较,如果没有净变化,则不会发生 SQL 操作(这是一种更昂贵的操作,因此只在刷新时执行)。

要检查实例的属性是否具有可执行的净变化,请使用Session.is_modified()方法。

method enable_relationship_loading(obj: object) → None

将对象与此Session关联以加载相关对象。

警告

enable_relationship_loading()存在于服务于特殊用例,并不建议一般使用。

通过relationship()映射的属性访问将尝试使用此Session作为连接的源来从数据库加载值。这些值将根据此对象上存在的外键和主键值进行加载 - 如果不存在,则这些关系将不可用。

对象将附加到此会话,但将不会参与任何持久化操作;对于几乎所有目的,其状态仍将保持“瞬态”或“分离”,除了关系加载的情况。

还请注意,反向引用通常不会按预期工作。在目标对象上修改与关系绑定的属性可能不会触发反向引用事件,如果有效值已从保存外键值中加载,则是如此。

Session.enable_relationship_loading()方法类似于relationship()上的load_on_pending标志。与该标志不同,Session.enable_relationship_loading()允许对象保持瞬态状态,同时仍然能够加载相关项目。

要使一个临时对象与Session相关联,可以通过Session.enable_relationship_loading()将其添加到Session中。如果该对象代表数据库中现有的标识,则应使用Session.merge()进行合并。

Session.enable_relationship_loading()在正常使用 ORM 时不会改善行为 - 对象引用应该在对象级别构建,而不是在外键级别构建,以便它们在 flush()继续之前以普通方式存在。此方法不适用于一般用途。

另请参见

relationship.load_on_pending - 此标志允许在待处理项目上对多对一关系进行逐个加载。

make_transient_to_detached() - 允许将对象添加到Session中而不发出 SQL,然后在访问时取消过期属性。

method execute(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, _parent_execute_state: Any | None = None, _add_event: Any | None = None) → Result[Any]

执行 SQL 表达式构造。

返回代表语句执行结果的Result对象。

例如:

from sqlalchemy import select
result = session.execute(
    select(User).where(User.id == 5)
)

Session.execute()的 API 契约类似于Connection.execute()的契约,是Connection的 2.0 风格版本。

从版本 1.4 开始更改:当使用 2.0 风格的 ORM 用法时,Session.execute()方法现在是 ORM 语句执行的主要点。

参数:

  • statement – 可执行语句(即Executable表达式,如select())。

  • params – 可选字典,或包含绑定参数值的字典列表。如果是单个字典,则执行单行;如果是字典列表,则将调用“executemany”。每个字典中的键必须对应于语句中存在的参数名称。

  • execution_options

    可选的执行选项字典,将与语句执行关联起来。此字典可以提供Connection.execution_options()所接受的选项子集,也可以提供仅在 ORM 上下文中理解的附加选项。

    另请参见

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments – 附加参数字典,用于确定绑定。可能包括“mapper”、“bind”或其他自定义参数。此字典的内容传递给Session.get_bind()方法。

返回:

一个Result对象。

method expire(instance: object, attribute_names: Iterable[str] | None = None) → None

使实例上的属性过期。

将实例的属性标记为过时。下次访问过期属性时,将向Session对象的当前事务上下文发出查询,以便为给定实例加载所有过期属性。请注意,高度隔离的事务将返回与之前在同一事务中读取的相同值,而不管该事务之外的数据库状态如何更改。

要同时使Session中的所有对象过期,请使用Session.expire_all()

Session对象的默认行为是在调用Session.rollback()Session.commit()方法时使所有状态过期,以便为新事务加载新状态。因此,仅在当前事务中发出非 ORM SQL 语句的情况下调用Session.expire()才有意义。

参数:

  • instance – 要刷新的实例。

  • attribute_names – 可选的字符串属性名称列表,指示要过期的属性子集。

另请参见

刷新/过期 - 介绍性材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expire_all() → None

使此会话中的所有持久实例过期。

当对持久实例上的任何属性进行下一次访问时,将使用Session对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与之前在同一事务中读取的相同值,而不管事务外数据库状态的更改如何。

要使单个对象及其上的单个属性过期,请使用Session.expire()

当调用Session.rollback()Session.commit()方法时,Session对象的默认行为是使所有状态过期,以便为新事务加载新状态。因此,通常不需要调用Session.expire_all(),假设事务是隔离的。

另请参阅

刷新/过期 - 简介材料

Session.expire()

Session.refresh()

Query.populate_existing()

method expunge(instance: object) → None

从此Session中删除实例。

这将释放所有对实例的内部引用。级联将根据expunge级联规则应用。

method expunge_all() → None

从此Session中删除所有对象实例。

这相当于在此Session中调用expunge(obj)以将所有对象从中清除。

method flush(objects: Sequence[Any] | None = None) → None

将所有对象更改刷新到数据库。

将所有待处理的对象创建、删除和修改操作写入数据库,作为 INSERTs、DELETEs、UPDATEs 等。操作会自动按照会话的工作单元依赖解析器的顺序进行排序。

数据库操作将在当前事务上下文中发出,并且不会影响事务的状态,除非发生错误,在这种情况下将回滚整个事务。您可以在事务中随意刷新(),以将更改从 Python 移动到数据库的事务缓冲区。

参数:

objects

可选;仅将刷新操作限制为仅操作给定集合中的元素。

此功能适用于极其狭窄的一组用例,其中特定对象可能需要在完全执行 flush()之前操作。不适用于一般用途。

method get(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O | None

根据给定的主键标识符返回一个实例,如果找不到则返回None

示例:

my_user = session.get(User, 5)

some_object = session.get(VersionedFoo, (5, 10))

some_object = session.get(
    VersionedFoo,
    {"id": 5, "version_id": 10}
)

版本 1.4 中的新功能:添加了Session.get(),该方法已从现已过时的Query.get()方法中移除。

Session.get() 是特殊的,因为它直接提供对Session的标识映射的访问。如果给定的主键标识符存在于本地标识映射中,则直接从该集合返回对象,并且不会发出 SQL,除非对象已被标记为完全过期。如果不存在,则执行 SELECT 来定位对象。

Session.get() 还会检查对象是否存在于标识映射中并标记为过期 - 会发出 SELECT 来刷新对象,并确保行仍然存在。如果不是,则引发 ObjectDeletedError

参数:

  • entity – 表示要加载的实体类型的映射类或Mapper

  • ident

    代表主键的标量、元组或字典。对于复合(例如多列)主键,应传递元组或字典。

    对于单列主键,标量调用形式通常是最快捷的。如果行的主键值是“5”,则调用如下:

    my_object = session.get(SomeClass, 5)
    

    元组形式通常按照它们与映射的Table对象的主键列对应的顺序排列,或者如果使用了Mapper.primary_key配置参数,则按照该参数的使用顺序排列。例如,如果一行的主键由整数数字“5, 10”表示,则调用将如下所示:

    my_object = session.get(SomeClass, (5, 10))
    

    字典形式应该将每个主键元素对应的映射属性名称作为键。如果映射类具有存储对象主键值的属性idversion_id,则调用将如下所示:

    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
    
  • options – 可选的加载器选项序列,将应用于查询(如果发出了查询)。

  • populate_existing – 导致该方法无条件地发出 SQL 查询并使用新加载的数据刷新对象,无论对象是否已存在。

  • with_for_update – 可选的布尔值True表示应该使用 FOR UPDATE,或者可以是一个包含标志的字典,表示一个更具体的用于 SELECT 的 FOR UPDATE 标志集合;标志应该与Query.with_for_update()的参数匹配。覆盖Session.refresh.lockmode参数。

  • execution_options

    可选的执行选项字典,如果发出了查询执行,则将与之相关联。此字典可以提供由Connection.execution_options()接受的选项的子集,并且还可以提供仅在 ORM 上下文中理解的其他选项。

    新版本中的 1.4.29。

    另请参见

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments

    用于确定绑定的其他参数的字典。可能包括“mapper”,“bind”或其他自定义参数。此字典的内容将传递给Session.get_bind()方法。

返回:

对象实例,或者None

method get_bind(mapper: _EntityBindKey[_O] | None = None, *, clause: ClauseElement | None = None, bind: _SessionBind | None = None, _sa_skip_events: bool | None = None, _sa_skip_for_implicit_returning: bool = False, **kw: Any) → Engine | Connection

返回此Session所绑定到的“绑定”。

“绑定”通常是Engine的一个实例,除非Session已经被明确地直接绑定到一个Connection的情况除外。

对于多次绑定或未绑定的Session,使用mapperclause参数来确定返回的适当绑定。

请注意,当通过 ORM 操作(例如Session.query()Session.flush()调用等)调用Session.get_bind()时,“mapper”参数通常存在。

解析的顺序是:

  1. 如果提供了 mapper 并且Session.binds存在,则根据使用的 mapper,然后根据使用的 mapped 类,然后根据 mapped 类的__mro__中存在的任何基类,从更具体的超类到更一般的超类来定位一个绑定。

  2. 如果给定了子句并且存在Session.binds,则基于Session.binds中存在的给定子句中找到的Table对象定位一个绑定。

  3. 如果存在Session.binds,则返回该绑定。

  4. 如果给定了子句,则尝试返回与最终与子句关联的MetaData相关联的绑定。

  5. 如果给定了映射器,则尝试返回与最终与映射器映射到的Table或其他可选择的绑定相关联的MetaData

  6. 找不到绑定时,将引发UnboundExecutionError

注意,Session.get_bind() 方法可以在用户定义的Session子类上被重写,以提供任何类型的绑定解析方案。请参见自定义垂直分区中的示例。

参数:

  • mapper – 可选的映射类或对应的Mapper实例。绑定可以首先从与此Session关联的“binds”映射中派生Mapper,其次通过查看与Mapper映射到的Table相关联的MetaData来获取。

  • clause – 一个ClauseElement(即select()text()等)。如果mapper参数不存在或无法生成绑定,则将搜索给定表达式构造的绑定元素,通常是与绑定的MetaData相关联的Table

另请参阅

分区策略(例如每个 Session 多个数据库后���)

Session.binds

Session.bind_mapper()

Session.bind_table()

method get_nested_transaction() → SessionTransaction | None

返回当前正在进行的嵌套事务,如果有的话。

版本 1.4 中的新功能。

method get_one(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) → _O

根据给定的主键标识符返回一个实例,如果未找到则引发异常。

如果查询未选择任何行,则引发sqlalchemy.orm.exc.NoResultFound

有关参数的详细文档,请参见方法Session.get()

版本 2.0.22 中的新功能。

返回:

对象实例。

另请参见

Session.get() - 相当的方法,而不是

如果未找到具有提供的主键的行,则返回None

method get_transaction() → SessionTransaction | None

返回当前正在进行的根事务,如果有的话。

版本 1.4 中的新功能。

classmethod identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) → _IdentityKeyType[Any]

继承自 sqlalchemy.orm.session._SessionClassMethods.identity_key 方法的 sqlalchemy.orm.session._SessionClassMethods

返回一个标识键。

这是identity_key()的别名。

attribute identity_map: IdentityMap

对象标识与对象本身的映射。

通过遍历Session.identity_map.values()可以访问当前会话中的所有持久对象的完整集合(即具有行标识的对象)。

另请参见

identity_key() - 用于生成此字典中使用的键的辅助函数。

method in_nested_transaction() → bool

如果此Session已开始嵌套事务(例如 SAVEPOINT),则返回 True。

版本 1.4 中的新功能。

method in_transaction() → bool

如果此Session已开始事务,则返回 True。

版本 1.4 中的新功能。

另请参见

Session.is_active

attribute info

用户可修改的字典。

此字典的初始值可以使用Session构造函数或sessionmaker构造函数或工厂方法的info参数进行填充。此处的字典始终局限于此Session,可以独立于所有其他Session对象进行修改。

method invalidate() → None

使用连接失效关闭此会话。

这是Session.close()的变体,还将确保在当前用于事务的每个Connection对象上调用Connection.invalidate()方法(通常只有一个连接,除非Session与多个引擎一起使用)。

当已知数据库处于不再安全使用连接的状态时,可以调用此方法。

下面说明了使用gevent时可能出现的Timeout异常的情况,这可能意味着应丢弃底层连接:

import gevent

try:
    sess = Session()
    sess.add(User())
    sess.commit()
except gevent.Timeout:
    sess.invalidate()
    raise
except:
    sess.rollback()
    raise

该方法还执行Session.close()执行的所有操作,包括清除所有 ORM 对象。

attribute is_active

如果此Session不处于“部分回滚”状态,则为 True。

在版本 1.4 中更改:Session 不再立即开始新事务,因此当首次实例化Session时,此属性将为 False。

“部分回滚”状态通常表示Session的刷新过程失败,并且必须发出Session.rollback()方法以完全回滚事务。

如果此Session根本不处于事务中,则在首次使用时Session将自动开始,因此在这种情况下Session.is_active将返回 True。

否则,如果此Session在事务内,并且该事务尚未在内部回滚,则Session.is_active也将返回 True。

另请参见

“由于在刷新期间发生的先前异常,此会话的事务已回滚。”(或类似内容)

Session.in_transaction()

method is_modified(instance: object, include_collections: bool = True) → bool

返回 True 如果给定的实例具有本地修改的属性。

此方法检索实例上每个受监视属性的历史记录,并将当前值与先前提交的值进行比较(如果有的话)。

实际上,这是一种更昂贵和准确的版本,用于检查给定实例是否存在于 Session.dirty 集合中;对每个属性的净“脏”状态进行了完整测试。

例如:

return session.is_modified(someobject)

这种方法有一些注意事项:

  • 当测试使用此方法时,存在于 Session.dirty 集合中的实例可能会报告 False。这是因为对象可能已通过属性变化接收到更改事件,从而将其放置在 Session.dirty 中,但最终状态与从数据库加载的状态相同,在这里没有净变化。

  • 当新值被应用时,标量属性可能没有记录先前设置的值,如果属性在接收到新值时没有被加载或已过期,则假定属性发生了变化,即使最终与其数据库值相比没有净变化,在大多数情况下,当设置事件发生时,SQLAlchemy 不需要“旧”值,因此,如果旧值不存在,则跳过发出 SQL 调用的开销,这是基于这样一个假设:通常需要更新标量值,并且在那些极少数情况下,其中不需要,平均而言,这比发出防御性 SELECT 更便宜。

    只有当属性容器的 active_history 标志设置为 True 时,才无条件地在设置时获取“旧”值。此标志通常设置为主键属性和非简单一对多的标量对象引用。要为任意映射列设置此标志,请使用 column_property() 中的 active_history 参数。

参数:

  • instance – 要测试是否存在待处理更改的映射实例。

  • include_collections – 指示是否应该在操作中包含多值集合。将其设置为 False 是一种检测仅基于本地列的属性(即标量列或一对多外键),这将导致此实例在刷新时进行更新。

method merge(instance: _O, *, load: bool = True, options: Sequence[ORMOption] | None = None) → _O

将给定实例的状态复制到此 Session 中对应的实例。

Session.merge() 检查源实例的主键属性,并尝试将其与会话中具有相同主键的实例进行协调。如果在本地找不到,则尝试根据主键从数据库加载对象,如果找不到,则创建一个新实例。然后将源实例上的每个属性的状态复制到目标实例。然后,该方法返回结果目标实例;原始源实例保持不变,并且如果尚未与Session 关联,则不与其关联。

此操作级联到相关实例,如果关联使用 cascade="merge" 进行映射。

有关合并的详细讨论,请参见合并。

参数:

  • instance – 要合并的实例。

  • load

    布尔值,当为 False 时,merge() 切换到“高性能”模式,导致它放弃发出历史事件以及所有数据库访问。此标志用于将对象图传输到从第二级缓存中的Session 中,或者将刚加载的对象传输到由工作线程或进程拥有的Session 中,而无需重新查询数据库。

    load=False 的使用情况添加了一个警告,即给定对象必须处于“干净”的状态,即没有任何待冲刷的更改 - 即使传入的对象是从任何一个Session 分离出来的。这样,当合并操作填充本地属性并级联到相关对象和集合时,值可以“按原样”放置到目标对象上,而不会生成任何历史或属性事件,并且无需将传入的数据与可能未加载的任何现有相关对象或集合进行协调。load=False 生成的结果对象始终为“干净”,因此只有给定对象也应为“干净”,否则这表明方法的错误使用。

  • options

    可选的加载器选项序列,在合并操作从数据库加载对象的现有版本时将应用于Session.get() 方法。

    新版本 1.4.24 中新增。

另请参阅

make_transient_to_detached() - 提供了将单个对象“合并”到Session 的另一种方法。

attribute new

在此Session中标记为“新”的所有实例的集合。

attribute no_autoflush

返回一个禁用自动冲刷的上下文管理器。

例如:

with session.no_autoflush:

    some_object = SomeClass()
    session.add(some_object)
    # won't autoflush
    some_object.related_thing = session.query(SomeRelated).first()

with: 块内进行的操作不会受到查询访问时发生的 flush 的影响。这在初始化一系列涉及现有数据库查询的对象时很有用,此时尚未完成的对象不应立即被 flush。

classmethod object_session(instance: object) → Session | None

继承自 sqlalchemy.orm.session._SessionClassMethods sqlalchemy.orm.session._SessionClassMethods.object_session 方法

返回一个对象所属的Session

这是 object_session() 方法的别名。

method prepare() → None

准备进行中的当前事务以进行两阶段提交。

如果没有进行中的事务,则此方法会引发一个InvalidRequestError

仅两阶段会话的根事务才能被准备。如果当前事务不是这样的事务,则会引发 InvalidRequestError

method query(*entities: _ColumnsClauseArgument[Any], **kwargs: Any) → Query[Any]

返回一个与此 Session 对应的新 Query 对象。

请注意,Query 对象在 SQLAlchemy 2.0 中已经是遗留的;现在使用 select() 构造 ORM 查询。

另请参阅

SQLAlchemy 统一教程

ORM 查询指南

旧版查询 API - 旧版 API 文档

method refresh(instance: object, attribute_names: Iterable[str] | None = None, with_for_update: ForUpdateParameter = None) → None

过期并刷新给定实例上的属性。

选定的属性将首先被过期,就像使用 Session.expire() 时一样;然后会向数据库发出 SELECT 语句,以当前事务中可用的当前值刷新基于列的属性。

如果对象已经急加载,那么以relationship()为导向的属性也将立即加载,使用最初加载时的相同的急加载策略。

1.4 版本新增:- Session.refresh() 方法还可以立即刷新急加载的属性。

relationship()定向属性通常使用select(或“lazy”)加载器策略将在属性名称集合中明确命名时也会加载**,使用immediate加载器策略发出用于属性的 SELECT 语句。如果惰性加载的关系未在Session.refresh.attribute_names中命名,则它们将保持为“惰性加载”属性,并且不会被隐式刷新。

从版本 2.0.4 开始更改:Session.refresh()方法现在将刷新在Session.refresh.attribute_names集合中明确命名的惰性加载的relationship()定向属性。

提示

虽然Session.refresh()方法能够刷新列和关系定向属性,但其主要重点是刷新单个实例上的本地列定向属性。对于更开放的“刷新”功能,包括能够同时刷新多个对象的属性并明确控制关系加载器策略,请改用填充现有功能。

请注意,高度隔离的事务将返回与先前在该事务中读取的相同值,而不考虑该事务之外数据库状态的更改。通常只在事务开始时数据库行尚未被访问时刷新属性才有意义。

参数:

  • attribute_names – 可选。一个包含字符串属性名称的可迭代集合,指示要刷新的属性子集。

  • with_for_update – 可选布尔值True表示应使用 FOR UPDATE,或者可以是一个包含标志的字典,指示用于 SELECT 的更具体的 FOR UPDATE 标志集;标志应与Query.with_for_update()参数匹配。取代Session.refresh.lockmode参数。

另请参阅

刷新/过期 - 入门材料

Session.expire()

Session.expire_all()

填充现有对象 - 允许任何 ORM 查询刷新对象,就像它们通常加载的那样。

method reset() → None

关闭事务资源和此Session使用的 ORM 对象,将会重置会话到其初始状态。

此方法提供了与Session.close()方法历史上提供的相同“仅重置”行为,其中Session的状态被重置,就像对象是全新的一样,并且可以再次使用。然后,此方法可能对将Session.close_resets_only设置为FalseSession对象有用,以便仍然可以使用“仅重置”行为。

新版本 2.0.22 中新增。

另请参阅

关闭操作 - 关于Session.close()Session.reset()语义的详细信息。

Session.close() - 当参数Session.close_resets_only设置为False时,类似的方法还会阻止重复使用Session

method rollback() → None

回滚当前进行中的事务。

如果没有进行中的事务,则此方法是一个传递方法。

该方法始终回滚最顶层的数据库事务,丢弃可能正在进行的任何嵌套事务。

另请参阅

回滚操作

事务管理

method scalar(statement: Executable, params: _CoreSingleExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → Any

执行语句并返回标量结果。

使用和参数与Session.execute()相同;返回结果是一个标量 Python 值。

method scalars(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) → ScalarResult[Any]

执行语句并将结果作为标量返回。

使用和参数与Session.execute()相同;返回结果是一个过滤对象ScalarResult,它将返回单个元素而不是Row对象。

返回:

一个ScalarResult对象

新版本 1.4.24 中新增:添加Session.scalars()

新版本 1.4.26 中新增:添加scoped_session.scalars()

另请参阅

选择 ORM 实体 - 对比 Session.execute()Session.scalars() 的行为

class sqlalchemy.orm.SessionTransaction

一个 Session 级别的事务。

SessionTransaction 是从 Session.begin()Session.begin_nested() 方法中生成的。它在现代用法中主要是一个为会话事务提供上下文管理器的内部对象。

SessionTransaction 交互的文档位于:管理事务。

在版本 1.4 中更改:与 SessionTransaction 对象直接交互的作用域和 API 方法已经简化。

另请参阅

管理事务

Session.begin()

Session.begin_nested()

Session.rollback()

Session.commit()

Session.in_transaction()

Session.in_nested_transaction()

Session.get_transaction()

Session.get_nested_transaction()

成员

嵌套, origin, 父级

类签名

sqlalchemy.orm.SessionTransaction (sqlalchemy.orm.state_changes._StateChange, sqlalchemy.engine.util.TransactionalContext)

attribute nested: bool = False

指示此事务是否为嵌套或 SAVEPOINT 事务。

SessionTransaction.nested 为 True 时,预期 SessionTransaction.parent 也将出现,并链接到封闭的 SessionTransaction

另请参见

SessionTransaction.origin

attribute origin: SessionTransactionOrigin

SessionTransaction 的来源。

指的是一个 SessionTransactionOrigin 实例,它是一个枚举,指示导致构建此 SessionTransaction 的源事件。

新版本 2.0 中新增。

attribute parent

SessionTransaction 的父 SessionTransaction

如果此属性为 None,表示此 SessionTransaction 处于堆栈顶部,并对应于真实的“COMMIT”/“ROLLBACK”块。 如果非 None,则这是一个“子事务”(刷新过程中使用的内部标记对象)或“嵌套”/保存点事��。 如果 SessionTransaction.nested 属性为 True,则这是一个保存点,如果为 False,则表示这是一个子事务。

class sqlalchemy.orm.SessionTransactionOrigin

指示 SessionTransaction 的来源。

此枚举存在于任何 SessionTransaction 对象的 SessionTransaction.origin 属性上。

新版本 2.0 中新增。

成员

AUTOBEGIN, BEGIN, BEGIN_NESTED, SUBTRANSACTION

类签名

sqlalchemy.orm.SessionTransactionOrigin (enum.Enum)

attribute AUTOBEGIN = 0

事务是由 autobegin 启动的。

attribute BEGIN = 1

事务是通过调用 Session.begin() 开始的。

attribute BEGIN_NESTED = 2

事务是通过 Session.begin_nested() 开始的。

attribute SUBTRANSACTION = 3

事务是一个内部的“子事务”。

会话工具

对象名称 描述
close_all_sessions() 关闭内存中的所有会话。
make_transient(instance) 更改给定实例的状态,使其成为瞬态。
make_transient_to_detached(instance) 使给定的瞬态实例分离。
object_session(instance) 返回给定实例所属的Session
was_deleted(object_) 如果给定对象在会话刷新中被删除,则返回 True。
function sqlalchemy.orm.close_all_sessions() → None

关闭内存中的所有会话。

此函数查询所有Session对象的全局注册表,并调用Session.close()关闭它们,将它们重置为干净状态。

此函数不适用于一般用途,但可能对拆卸方案中的测试套件有用。

版本 1.3 中的新功能。

function sqlalchemy.orm.make_transient(instance: object) → None

更改给定实例的状态,使其为瞬态。

注意

make_transient()是仅适用于高级用例的特殊函数。

假定给定的映射实例处于持久或分离状态。该函数将删除其与任何Session的关联以及其InstanceState.identity。其效果是对象将表现得像是新构造的,但保留在调用时加载的任何属性/集合值。如果此对象曾因使用Session.delete()而被删除,则InstanceState.deleted标志也将被重置。

警告

make_transient() “取消过期”或以其他方式急切加载在调用函数时尚未加载的 ORM 映射属性。这包括:

  • 通过Session.expire()过期

  • 作为提交会话事务的自然效果而过期,例如Session.commit()

  • 通常是延迟加载,但目前尚未加载

  • 被“延迟加载”(参见限制加载的列与列延迟)且尚未加载

  • 在加载此对象的查询中不存在,例如在联接表继承和其他场景中常见的情况。

调用 make_transient() 后,像上面这样未加载的属性通常在访问时将解析为值 None,或者对于集合定向属性为一个空集合。由于对象是瞬态的,并且未关联任何数据库标识,因此它将不再检索这些值。

另请参阅

make_transient_to_detached()

function sqlalchemy.orm.make_transient_to_detached(instance: object) → None

使给定的瞬态实例 分离。

注意

make_transient_to_detached() 是一个仅限于高级用例的特殊情况函数。

在给定实例上的所有属性历史都将被重置,就像实例是从查询中新加载的一样。丢失的属性将被标记为过期。对象的主键属性将被制作为实例的“键”,这些主键属性是必需的。

然后对象可以被添加到一个会话中,或者可能与 load=False 标志合并,此时它将看起来像是以这种方式加载,而不发出 SQL。

这是一个特殊的用例函数,与对 Session.merge() 的正常调用不同,因为可以制造给定的持久状态而不进行任何 SQL 调用。

另请参阅

make_transient()

Session.enable_relationship_loading()

function sqlalchemy.orm.object_session(instance: object) → Session | None

返回给定实例所属的 Session

这与 InstanceState.session 访问器本质上是相同的。有关详细信息,请参阅该属性。

function sqlalchemy.orm.util.was_deleted(object_: object) → bool

返回 True,如果给定的对象在会话刷新内被删除。

不管对象是持久的还是分离的,都是如此。

另请参阅

InstanceState.was_deleted

属性和状态管理实用程序

这些函数由 SQLAlchemy 属性调制 API 提供,以提供一个详细的接口来处理实例、属性值和历史。当构造事件监听函数时,其中一些函数是有用的,比如 ORM 事件 中描述的那些函数。

对象名称 描述
del_attribute(instance, key) 删除属性的值,触发历史事件。
flag_dirty(instance) 标记一个实例为“脏”状态,而不需要特定的属性名称。
flag_modified(instance, key) 将实例上的属性标记为“已修改”。
get_attribute(instance, key) 获取属性的值,触发任何所需的可调用函数。
get_history(obj, key[, passive]) 返回给定对象和属性键的History记录。
History 已添加、未更改和已删除值的 3 元组,表示在受监控属性上发生的更改。
init_collection(obj, key) 初始化一个集合属性并返回集合适配器。
instance_state 返回给定映射对象的InstanceState
is_instrumented(instance, key) 如果给定实例上的给定属性由 attributes 包进行了插装,则返回 True。
object_state(instance) 给定一个对象,返回与该对象关联的InstanceState
set_attribute(instance, key, value[, initiator]) 设置属性的值,触发历史事件。
set_committed_value(instance, key, value) 设置属性的值,不触发历史事件。
function sqlalchemy.orm.util.object_state(instance: _T) → InstanceState[_T]

给定一个对象,返回与该对象关联的InstanceState

如果未配置映射,则引发sqlalchemy.orm.exc.UnmappedInstanceError

相同的功能可以通过inspect()函数获得,如下所示:

inspect(instance)

使用检查系统将在实例不属于映射的情况下引发sqlalchemy.exc.NoInspectionAvailable

function sqlalchemy.orm.attributes.del_attribute(instance: object, key: str) → None

删除属性的值,触发历史事件。

无论直接应用于类的插装如何,都可以使用此函数,即不需要描述符。自定义属性管理方案将需要使用此方法来建立由 SQLAlchemy 理解的属性状态。

function sqlalchemy.orm.attributes.get_attribute(instance: object, key: str) → Any

获取属性的值,触发任何所需的可调用函数。

无论直接应用于类的仪器,都可以使用此功能,即不需要描述符。自定义属性管理方案将需要使用此方法来使用 SQLAlchemy 所理解的属性状态。

function sqlalchemy.orm.attributes.get_history(obj: object, key: str, passive: PassiveFlag = symbol('PASSIVE_OFF')) → History

返回给定对象和属性键的History记录。

这是给定属性的预刷新历史记录,每次Session刷新更改到当前数据库事务时都会重置它。

注意

首选使用AttributeState.historyAttributeState.load_history()访问器来检索实例属性的History

参数:

  • obj – 一个其类由属性包仪器化的对象。

  • key – 字符串属性名称。

  • passive – 如果值尚不存在,则指示属性的加载行为。这是一个位标志属性,默认为PASSIVE_OFF,表示应发出所有必要的 SQL。

另请参见

AttributeState.history

AttributeState.load_history() - 如果值在本地不存在,则使用加载器可调用检索历史。

function sqlalchemy.orm.attributes.init_collection(obj: object, key: str) → CollectionAdapter

初始化一个集合属性并返回集合适配器。

此函数用于为先前未加载的属性提供直接访问集合内部。例如:

collection_adapter = init_collection(someobject, 'elements')
for elem in values:
    collection_adapter.append_without_event(elem)

对于执行上述操作的更简单方法,请参见set_committed_value()

参数:

  • obj – 一个映射对象

  • key – 集合所在的字符串属性名称。

function sqlalchemy.orm.attributes.flag_modified(instance: object, key: str) → None

将实例上的属性标记为“已修改”。

这会在实例上设置“已修改”标志,并为给定属性建立一个无条件的更改事件。属性必须具有值,否则会引发InvalidRequestError

要标记一个对象为“脏”,而不引用任何特定属性,以便在刷新时考虑到它,使用flag_dirty()调用。

另请参见

flag_dirty()

function sqlalchemy.orm.attributes.flag_dirty(instance: object) → None

将实例标记为“脏”,而不提及任何特定属性。

这是一个特殊操作,允许对象通过刷新流程进行拦截,例如 SessionEvents.before_flush()。请注意,对于没有更改的对象,在刷新过程中不会发出任何 SQL,即使通过此方法标记为脏。但是,SessionEvents.before_flush() 处理程序将能够在 Session.dirty 集合中看到对象,并可能对其进行更改,然后这些更改将包含在发出的 SQL 中。

自 1.2 版新功能。

另请参阅

flag_modified()

function sqlalchemy.orm.attributes.instance_state()

返回给定映射对象的 InstanceState

此函数是 object_state() 的内部版本。此处推荐使用 object_state() 和/或 inspect() 函数,因为它们会在给定对象未映射时各自发出信息丰富的异常。

function sqlalchemy.orm.instrumentation.is_instrumented(instance, key)

如果给定实例上的给定属性由 attributes 包进行仪器化,则返回 True。

无论直接应用于类的仪器如何,都可以使用此函数,即不需要描述符。

function sqlalchemy.orm.attributes.set_attribute(instance: object, key: str, value: Any, initiator: AttributeEventToken | None = None) → None

设置属性的值,并触发历史事件。

无论直接应用于类的仪器如何,都可以使用此函数,即不需要描述符。自定义属性管理方案将需要使用此方法来建立由 SQLAlchemy 理解的属性状态。

参数:

  • instance – 将要修改的对象

  • key – 属性的字符串名称

  • value – 要分配的值

  • initiator

    一个 Event 的实例,可能已从前一个事件侦听器传播。当在现有事件侦听器函数中使用 set_attribute() 函数时,其中提供了一个 Event 对象;该对象可用于跟踪事件链的来源。

    自 1.2.3 版新功能。

function sqlalchemy.orm.attributes.set_committed_value(instance, key, value)

设置没有历史事件的属性值。

取消任何先前存在的历史。值应为标量值(对于保存标量的属性)或可迭代对象(对于任何保存集合的属性)。

当惰性加载器触发并从数据库加载附加数据时,使用的是相同的基础方法。特别是,该方法可被应用代码使用,通过单独的查询加载了额外的属性或集合,然后可以将其附加到实例上,就像它是其原始加载状态的一部分一样。

class sqlalchemy.orm.attributes.History

一个由添加、未更改和已删除值组成的 3 元组,表示在一个被检测的属性上发生的变化。

获取对象上特定属性的History对象的最简单方法是使用inspect()函数:

from sqlalchemy import inspect

hist = inspect(myobject).attrs.myattribute.history

每个元组成员都是一个可迭代序列:

  • added - 添加到属性的项目的集合(第一个元组元素)。

  • unchanged - 在属性上没有更改的项目的集合(第二个元组元素)。

  • deleted - 从属性中删除的项目的集合(第三个元组元素)。

成员

added, deleted, empty(), has_changes(), non_added(), non_deleted(), sum(), unchanged

类签名

sqlalchemy.orm.Historybuiltins.tuple

attribute added: Tuple[()] | List[Any]

字段编号 0 的别名

attribute deleted: Tuple[()] | List[Any]

字段编号 2 的别名

method empty() → bool

如果这个History没有更改并且没有现有的未更改状态,则返回 True。

method has_changes() → bool

如果这个History有更改,则返回 True。

method non_added() → Sequence[Any]

返回未更改 + 已删除的集合。

method non_deleted() → Sequence[Any]

返回已添加 + 未更改的集合。

method sum() → Sequence[Any]

返回已添加 + 未更改 + 已删除的集合。

attribute unchanged: Tuple[()] | List[Any]

字段编号 1 的别名

posted @ 2024-06-22 11:37  绝不原创的飞龙  阅读(15)  评论(0编辑  收藏  举报