SQLAlchemy 2.0 文档
SQLAlchemy ORM
- ORM 快速入门
- ORM 映射类配置
- 关系配置
- ORM 查询指南
- 使用 Session
- 事件和内部机制
- ORM 扩展
- ORM 示例
项目版本
ORM API 查询功能¶
ORM 加载器选项¶
加载器选项是一些对象,当传递给 Select.options() 方法(Select 对象或类似的 SQL 构造)时,会影响列和面向关系的属性的加载。 大多数加载器选项都派生自 Load 层次结构。 有关使用加载器选项的完整概述,请参阅以下链接部分。
另请参阅
列加载选项 - 详细说明影响如何加载列和 SQL 表达式映射属性的映射器和加载选项
关系加载技术 - 详细说明影响如何加载
relationship()映射属性的关系和加载选项
ORM 执行选项¶
ORM 级别的执行选项是可以使用 Session.execute.execution_options 参数(Session 方法(如 Session.execute() 和 Session.scalars())接受的字典参数)与语句执行关联的关键字选项,或者通过使用 Executable.execution_options() 方法将它们直接与要调用的语句关联,该方法接受它们作为任意关键字参数。
ORM 级别选项与 Connection.execution_options() 中记录的核心级别执行选项不同。 重要的是要注意,下面讨论的 ORM 选项与核心级别方法 Connection.execution_options() 或 Engine.execution_options() 不 兼容;即使 Engine 或 Connection 与正在使用的 Session 关联,这些选项也会在此级别被忽略。
在本节中,将使用 Executable.execution_options() 方法样式进行示例说明。
填充现有对象¶
populate_existing 执行选项确保对于加载的所有行,Session 中的相应实例将被完全刷新 - 擦除对象中的任何现有数据(包括待处理的更改),并替换为从结果加载的数据。
示例用法如下所示
>>> stmt = select(User).execution_options(populate_existing=True)
>>> result = session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...
通常,ORM 对象仅加载一次,如果它们与后续结果行中的主键匹配,则该行不会应用于该对象。 这既是为了保留对象上待处理的、未刷新的更改,也是为了避免刷新已存在的数据的开销和复杂性。 Session 假定高度隔离事务的默认工作模型,并且在期望数据在事务内本地更改之外发生更改的程度上,这些用例将使用显式步骤(如本方法)来处理。
使用 populate_existing,可以刷新与查询匹配的任何对象集,并且还可以控制关系加载器选项。 例如,要在刷新实例的同时刷新一组相关的对象
stmt = (
select(User)
.where(User.name.in_(names))
.execution_options(populate_existing=True)
.options(selectinload(User.addresses))
)
# will refresh all matching User objects as well as the related
# Address objects
users = session.execute(stmt).scalars().all()populate_existing 的另一个用例是支持各种属性加载功能,这些功能可以更改每个查询的属性加载方式。 应用此选项的选项包括
可以修改加载器策略加载内容的
PropComparator.and_()方法选择要刷新哪些属性的
load_only()选项
populate_existing 执行选项等效于 Query.populate_existing() 方法,在 1.x 风格 ORM 查询中。
自动刷新¶
当此选项作为 False 传递时,将导致 Session 不调用“自动刷新”步骤。 它等效于使用 Session.no_autoflush 上下文管理器来禁用自动刷新
>>> stmt = select(User).execution_options(autoflush=False)
>>> session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...
此选项也适用于启用 ORM 的 Update 和 Delete 查询。
autoflush 执行选项等效于 Query.autoflush() 方法,在 1.x 风格 ORM 查询中。
另请参阅
使用 Yield Per 获取大型结果集¶
yield_per 执行选项是一个整数值,它将导致 Result 一次仅缓冲有限数量的行和/或 ORM 对象,然后再将数据提供给客户端。
通常,ORM 会立即获取所有行,为每个行构造 ORM 对象,并将这些对象组装到单个缓冲区中,然后再将此缓冲区作为要返回的行源传递给 Result 对象。 此行为的基本原理是允许连接急切加载、结果唯一化以及结果处理逻辑的一般情况(依赖于身份映射维护结果集中每个对象在获取时的状态一致性)等功能的正确行为。
yield_per 选项的目的是更改此行为,以便针对迭代非常大的结果集(例如 > 10K 行)优化 ORM 结果集,在这种情况下,用户已确定上述模式不适用。 当使用 yield_per 时,ORM 将改为将 ORM 结果批处理到子集合中,并在迭代 Result 对象时从每个子集合单独生成行,以便 Python 解释器无需声明非常大的内存区域,这既耗时又导致过多的内存使用。 此选项会影响数据库游标的使用方式,以及 ORM 如何构造要传递给 Result 的行和对象。
提示
从上面可以看出,Result 必须以可迭代的方式使用,即使用迭代(如 for row in result)或使用部分行方法(如 Result.fetchmany() 或 Result.partitions())。 调用 Result.all() 将会破坏使用 yield_per 的目的。
使用 yield_per 等效于同时使用 Connection.execution_options.stream_results 执行选项(如果后端支持,则选择使用服务器端游标)和返回的 Result 对象上的 Result.yield_per() 方法,该方法建立要获取的行的固定大小以及将一次构造的 ORM 对象的相应限制。
提示
yield_per 现在也作为核心执行选项提供,在 使用服务器端游标(又名流式结果) 中详细描述。 本节详细介绍了 yield_per 作为 ORM Session 的执行选项的用法。 该选项在这两种上下文中表现得尽可能相似。
与 ORM 一起使用时,yield_per 必须通过给定语句上的 Executable.execution_options() 方法或通过将其传递给 Session.execute.execution_options 参数(Session.execute() 或其他类似的 Session 方法(如 Session.scalars()))来建立。 以下说明了获取 ORM 对象的典型用法
>>> stmt = select(User).execution_options(yield_per=10)
>>> for user_obj in session.scalars(stmt):
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...上面的代码等效于下面的示例,该示例结合使用了 Connection.execution_options.stream_results 和 Connection.execution_options.max_row_buffer 核心级执行选项以及 Result.yield_per() 方法(Result 的方法)
# equivalent code
>>> stmt = select(User).execution_options(stream_results=True, max_row_buffer=10)
>>> for user_obj in session.scalars(stmt).yield_per(10):
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...yield_per 也常与 Result.partitions() 方法结合使用,该方法将按分组分区迭代行。 每个分区的大小默认为传递给 yield_per 的整数值,如下例所示
>>> stmt = select(User).execution_options(yield_per=10)
>>> for partition in session.scalars(stmt).partitions():
... for user_obj in partition:
... print(user_obj)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
...
>>> # ... rows continue ...yield_per 执行选项与使用集合时的 “子查询”急切加载 加载或 “连接”急切加载 不兼容。 它可能与 “select in”急切加载 兼容,前提是数据库驱动程序支持多个独立的游标。
此外,yield_per 执行选项与 Result.unique() 方法不兼容;由于此方法依赖于存储所有行的完整身份集,因此必然会破坏使用 yield_per 的目的,即处理任意数量的行。
在版本 1.4.6 中更改: 当从 Result 对象中提取 ORM 行时,如果该对象同时使用了 Result.unique() 过滤器和 yield_per 执行选项,则会引发异常。
当在 1.x 风格 ORM 用法中使用旧版 Query 对象时,Query.yield_per() 方法将具有与 yield_per 执行选项相同的结果。
另请参阅
身份令牌¶
“身份令牌”是可以在新加载对象的 身份键 中关联的任意值。 此元素的存在首先是为了支持执行按行“分片”的扩展,其中对象可以从任意数量的特定数据库表副本中加载,这些副本仍然具有重叠的主键值。 “身份令牌”的主要使用者是 水平分片 扩展,它为在特定数据库表的多个“分片”之间持久化对象提供了一个通用框架。
identity_token 执行选项可以基于每个查询使用,以直接影响此令牌。 直接使用它,可以在 Session 中填充具有相同主键和源表但不同“身份”的对象的多个实例。
一个这样的示例是在 Session 中填充来自不同模式中同名表的对象,使用 模式名称转换 功能,该功能可以影响查询范围内的模式选择。 给定如下映射
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class MyTable(Base):
__tablename__ = "my_table"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]上面类的默认“schema”名称是 None,这意味着不会将模式限定写入 SQL 语句。 但是,如果我们使用 Connection.execution_options.schema_translate_map,将 None 映射到备用模式,我们可以将 MyTable 的实例放置到两个不同的模式中
engine = create_engine(
"postgresql+psycopg://scott:tiger@localhost/test",
)
with Session(
engine.execution_options(schema_translate_map={None: "test_schema"})
) as sess:
sess.add(MyTable(name="this is schema one"))
sess.commit()
with Session(
engine.execution_options(schema_translate_map={None: "test_schema_2"})
) as sess:
sess.add(MyTable(name="this is schema two"))
sess.commit()上面的两个代码块每次都创建一个链接到不同模式转换映射的 Session 对象,并且 MyTable 的实例被持久化到 test_schema.my_table 和 test_schema_2.my_table 中。
上面的 Session 对象是独立的。 如果我们想在一个事务中持久化这两个对象,我们需要使用 水平分片 扩展来执行此操作。
但是,我们可以演示在一个会话中查询这些对象,如下所示
with Session(engine) as sess:
obj1 = sess.scalar(
select(MyTable)
.where(MyTable.id == 1)
.execution_options(
schema_translate_map={None: "test_schema"},
identity_token="test_schema",
)
)
obj2 = sess.scalar(
select(MyTable)
.where(MyTable.id == 1)
.execution_options(
schema_translate_map={None: "test_schema_2"},
identity_token="test_schema_2",
)
)obj1 和 obj2 彼此不同。 但是,它们都引用 MyTable 类的 primary key id 1,但它们是不同的。 这就是 identity_token 的作用,我们可以在检查每个对象时看到,我们在其中查看 InstanceState.key 以查看两个不同的身份令牌
>>> from sqlalchemy import inspect
>>> inspect(obj1).key
(<class '__main__.MyTable'>, (1,), 'test_schema')
>>> inspect(obj2).key
(<class '__main__.MyTable'>, (1,), 'test_schema_2')当使用 水平分片 扩展时,上述逻辑会自动发生。
在版本 2.0.0rc1 中新增: - 添加了 identity_token ORM 级别执行选项。
从启用 ORM 的 SELECT 和 DML 语句中检查实体和列¶
select() 构造,以及 insert()、update() 和 delete() 构造(对于后者的 DML 构造,从 SQLAlchemy 1.4.33 开始),都支持检查在其中创建这些语句的实体,以及结果集中将返回的列和数据类型的能力。
对于 Select 对象,此信息可从 Select.column_descriptions 属性获得。 此属性的操作方式与旧版 Query.column_descriptions 属性相同。 返回的格式是字典列表
>>> from pprint import pprint
>>> user_alias = aliased(User, name="user2")
>>> stmt = select(User, User.id, user_alias)
>>> pprint(stmt.column_descriptions)
[{'aliased': False,
'entity': <class 'User'>,
'expr': <class 'User'>,
'name': 'User',
'type': <class 'User'>},
{'aliased': False,
'entity': <class 'User'>,
'expr': <....InstrumentedAttribute object at ...>,
'name': 'id',
'type': Integer()},
{'aliased': True,
'entity': <AliasedClass ...; User>,
'expr': <AliasedClass ...; User>,
'name': 'user2',
'type': <class 'User'>}]当 Select.column_descriptions 与非 ORM 对象(例如纯 Table 或 Column 对象)一起使用时,条目将包含有关所有情况下返回的单个列的基本信息
>>> stmt = select(user_table, address_table.c.id)
>>> pprint(stmt.column_descriptions)
[{'expr': Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False),
'name': 'id',
'type': Integer()},
{'expr': Column('name', String(), table=<user_account>, nullable=False),
'name': 'name',
'type': String()},
{'expr': Column('fullname', String(), table=<user_account>),
'name': 'fullname',
'type': String()},
{'expr': Column('id', Integer(), table=<address>, primary_key=True, nullable=False),
'name': 'id_1',
'type': Integer()}]在版本 1.4.33 中变更:当 Select.column_descriptions 属性用于非 ORM 启用的 Select 时,现在会返回值。 以前,这将引发 NotImplementedError。
对于 insert()、update() 和 delete() 构造,有两个单独的属性。 一个是 UpdateBase.entity_description,它返回有关 DML 构造将影响的主要 ORM 实体和数据库表的信息
>>> from sqlalchemy import update
>>> stmt = update(User).values(name="somename").returning(User.id)
>>> pprint(stmt.entity_description)
{'entity': <class 'User'>,
'expr': <class 'User'>,
'name': 'User',
'table': Table('user_account', ...),
'type': <class 'User'>}提示
UpdateBase.entity_description 包括一个条目 "table",它实际上是语句要插入、更新或删除的表,这不总是与类可能映射到的 SQL “selectable” 相同。 例如,在连接表继承场景中,"table" 将引用给定实体的本地表。
另一个是 UpdateBase.returning_column_descriptions,它以与 Select.column_descriptions 大致相似的方式提供有关 RETURNING 集合中列的信息
>>> pprint(stmt.returning_column_descriptions)
[{'aliased': False,
'entity': <class 'User'>,
'expr': <sqlalchemy.orm.attributes.InstrumentedAttribute ...>,
'name': 'id',
'type': Integer()}]在版本 1.4.33 中新增:添加了 UpdateBase.entity_description 和 UpdateBase.returning_column_descriptions 属性。
其他 ORM API 构造¶
| 对象名称 | 描述 |
|---|---|
aliased(element[, alias, name, flat, ...]) |
生成给定元素的别名,通常是 |
表示映射类的“别名”形式,用于 Query。 |
|
为 |
|
由 |
|
join(left, right[, onclause, isouter, ...]) |
在 left 和 right 子句之间生成内连接。 |
outerjoin(left, right[, onclause, full]) |
在 left 和 right 子句之间生成左外连接。 |
with_loader_criteria(entity_or_base, where_criteria[, loader_only, include_aliases, ...]) |
为特定实体的所有出现次数的加载添加额外的 WHERE 条件。 |
with_parent(instance, prop[, from_entity]) |
创建过滤条件,使用已建立的 |
- function sqlalchemy.orm.aliased(element: _EntityType[_O] | FromClause, alias: FromClause | None = None, name: str | None = None, flat: bool = False, adapt_on_names: bool = False) → AliasedClass[_O] | FromClause | AliasedType[_O]¶
生成给定元素的别名,通常是
AliasedClass实例。例如:
my_alias = aliased(MyClass) stmt = select(MyClass, my_alias).filter(MyClass.id > my_alias.id) result = session.execute(stmt)
aliased()函数用于创建映射类到新 selectable 的临时映射。 默认情况下,selectable 是从通常映射的 selectable(通常是Table)使用FromClause.alias()方法生成的。 但是,aliased()也可用于将类链接到新的select()语句。 此外,with_polymorphic()函数是aliased()的变体,旨在指定所谓的“多态 selectable”,它对应于多个连接继承子类的联合。为了方便起见,
aliased()函数还接受纯FromClause构造,例如Table或select()构造。 在这些情况下,FromClause.alias()方法在对象上被调用,并返回新的Alias对象。 在这种情况下,返回的Alias未进行 ORM 映射。- 参数:
element¶ – 要别名的元素。 通常是映射类,但为了方便起见,也可以是
FromClause元素。alias¶ – 可选的 selectable 单元,用于将元素映射到该单元。 这通常用于将对象链接到子查询,并且应该是别名化的 select 构造,就像从
Query.subquery()方法或Select.subquery()或Select.alias()方法生成的select()构造一样。name¶ – 可选的字符串名称,用于别名,如果未由
alias参数指定。 该名称,除其他外,构成将通过Query对象返回的元组访问的属性名称。 当创建Join对象的别名时,不支持此参数。flat¶ –
布尔值,将传递给
FromClause.alias()调用,以便Join对象的别名将别名化连接内部的各个表,而不是创建子查询。 这通常被所有现代数据库支持,关于右嵌套连接,并且通常产生更高效的查询。当
aliased.flat与aliased.name结合使用时,生成的连接将使用类似于<prefix>_<tablename>的命名方案来别名化各个表。 此命名方案仅用于可见性/调试目的,具体方案如有更改,恕不另行通知。在版本 2.0.32 中新增:添加了对结合
aliased.name和aliased.flat的支持。 以前,这将引发NotImplementedError。adapt_on_names¶ –
如果为 True,则当将 ORM 实体的映射列映射到给定 selectable 的列时,将使用更宽松的“匹配” - 如果给定的 selectable 没有与实体上的列对应的列,则将执行基于名称的匹配。 这种情况的用例是将实体与某些派生的 selectable 关联,例如使用聚合函数的 selectable
class UnitPrice(Base): __tablename__ = "unit_price" ... unit_id = Column(Integer) price = Column(Numeric) aggregated_unit_price = ( Session.query(func.sum(UnitPrice.price).label("price")) .group_by(UnitPrice.unit_id) .subquery() ) aggregated_unit_price = aliased( UnitPrice, alias=aggregated_unit_price, adapt_on_names=True )
在上面,引用
aggregated_unit_price上.price的函数将返回func.sum(UnitPrice.price).label('price')列,因为它与名称“price”匹配。 通常,“price”函数与实际的UnitPrice.price列没有任何“列对应关系”,因为它不是原始列的代理。
- class sqlalchemy.orm.util.AliasedClass¶
表示映射类的“别名”形式,用于 Query。
ORM 等效于
alias()构造,此对象使用__getattr__方案模仿映射类,并维护对真实Alias对象的引用。AliasedClass的主要目的是充当 ORM 生成的 SQL 语句中的替代项,以便现有的映射实体可以在多个上下文中使用。 一个简单的例子# find all pairs of users with the same name user_alias = aliased(User) session.query(User, user_alias).join( (user_alias, User.id > user_alias.id) ).filter(User.name == user_alias.name)
AliasedClass也能够将现有的映射类映射到全新的 selectable,前提是此 selectable 与现有的映射 selectable 在列方面兼容,并且它可以在映射中配置为relationship()的目标。 请参阅下面的链接以获取示例。AliasedClass对象通常使用aliased()函数构造。 当使用with_polymorphic()函数时,它也会通过额外的配置生成。结果对象是
AliasedClass的实例。 此对象实现了一种属性方案,该方案生成与原始映射类相同的属性和方法接口,允许AliasedClass与任何适用于原始类的属性技术兼容,包括混合属性(请参阅 混合属性)。可以使用
inspect()检查AliasedClass的底层Mapper、别名化的 selectable 和其他信息from sqlalchemy import inspect my_alias = aliased(MyClass) insp = inspect(my_alias)
结果检查对象是
AliasedInsp的实例。类签名
class
sqlalchemy.orm.AliasedClass(sqlalchemy.inspection.Inspectable,sqlalchemy.orm.ORMColumnsClauseRole)
- class sqlalchemy.orm.util.AliasedInsp¶
为
AliasedClass对象提供检查接口。AliasedInsp对象是使用inspect()函数为AliasedClass返回的from sqlalchemy import inspect from sqlalchemy.orm import aliased my_alias = aliased(MyMappedClass) insp = inspect(my_alias)
AliasedInsp上的属性包括entity- 表示的AliasedClass。mapper- 映射底层类的Mapper。name- 别名的名称。 也用作从Query返回的结果元组中的属性名称。with_polymorphic_mappers-Mapper对象的集合,指示AliasedClass的 select 构造中表达的所有 mapper。polymorphic_on- 备用列或 SQL 表达式,将用作多态加载的“鉴别器”。
另请参阅
类签名
class
sqlalchemy.orm.AliasedInsp(sqlalchemy.orm.ORMEntityColumnsClauseRole,sqlalchemy.orm.ORMFromClauseRole,sqlalchemy.sql.cache_key.HasCacheKey,sqlalchemy.orm.base.InspectionAttr,sqlalchemy.util.langhelpers.MemoizedSlots,sqlalchemy.inspection.Inspectable,typing.Generic)
- class sqlalchemy.orm.Bundle¶
由
Query在一个命名空间下返回的 SQL 表达式分组。Bundle本质上允许嵌套由面向列的Query对象返回的基于元组的结果。 它也可以通过简单的子类化进行扩展,其中主要的覆盖能力是如何返回表达式集,允许后处理以及自定义返回类型,而无需涉及 ORM 标识映射类。另请参阅
成员
__init__(), c, columns, create_row_processor(), is_aliased_class, is_bundle, is_clause_element, is_mapper, label(), single_entity
类签名
class
sqlalchemy.orm.Bundle(sqlalchemy.orm.ORMColumnsClauseRole,sqlalchemy.sql.annotation.SupportsCloneAnnotations,sqlalchemy.sql.cache_key.MemoizedHasCacheKey,sqlalchemy.inspection.Inspectable,sqlalchemy.orm.base.InspectionAttr)-
method
sqlalchemy.orm.Bundle.__init__(name: str, *exprs: _ColumnExpressionArgument[Any], **kw: Any)¶ 构造一个新的
Bundle。例如:
bn = Bundle("mybundle", MyClass.x, MyClass.y) for row in session.query(bn).filter(bn.c.x == 5).filter(bn.c.y == 4): print(row.mybundle.x, row.mybundle.y)
-
attribute
sqlalchemy.orm.Bundle.c: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]¶ Bundle.columns的别名。
-
attribute
sqlalchemy.orm.Bundle.columns: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]¶ 此
Bundle引用的 SQL 表达式的命名空间。例如:
bn = Bundle("mybundle", MyClass.x, MyClass.y) q = sess.query(bn).filter(bn.c.x == 5)
也支持 Bundle 的嵌套
b1 = Bundle( "b1", Bundle("b2", MyClass.a, MyClass.b), Bundle("b3", MyClass.x, MyClass.y), ) q = sess.query(b1).filter(b1.c.b2.c.a == 5).filter(b1.c.b3.c.y == 9)
另请参阅
-
method
sqlalchemy.orm.Bundle.create_row_processor(query: Select[Any], procs: Sequence[Callable[[Row[Any]], Any]], labels: Sequence[str]) → Callable[[Row[Any]], Any]¶ 为此
Bundle生成 “行处理” 函数。子类可以重写此方法,以便在获取结果时提供自定义行为。此方法在查询执行时被传递 statement 对象和一组 “行处理器” 函数;这些处理器函数在给定结果行时将返回单个属性值,然后可以将其适配为任何类型的返回数据结构。
下面的示例说明了如何用纯 Python 字典替换通常的
Row返回结构from sqlalchemy.orm import Bundle class DictBundle(Bundle): def create_row_processor(self, query, procs, labels): "Override create_row_processor to return values as dictionaries" def proc(row): return dict(zip(labels, (proc(row) for proc in procs))) return proc
来自上述
Bundle的结果将返回字典值bn = DictBundle("mybundle", MyClass.data1, MyClass.data2) for row in session.execute(select(bn)).where(bn.c.data1 == "d1"): print(row.mybundle["data1"], row.mybundle["data2"])
-
attribute
sqlalchemy.orm.Bundle.is_aliased_class = False¶ 如果此对象是
AliasedClass的实例,则为 True。
-
attribute
sqlalchemy.orm.Bundle.is_bundle = True¶ 如果此对象是
Bundle的实例,则为 True。
-
attribute
sqlalchemy.orm.Bundle.is_clause_element = False¶ 如果此对象是
ClauseElement的实例,则为 True。
-
attribute
sqlalchemy.orm.Bundle.is_mapper = False¶ 如果此对象是
Mapper的实例,则为 True。
-
method
sqlalchemy.orm.Bundle.label(name)¶ 提供此
Bundle的副本,并传递新的标签。
-
attribute
sqlalchemy.orm.Bundle.single_entity = False¶ 如果为 True,则对单个 Bundle 的查询将作为单个实体返回,而不是键值元组中的元素返回。
-
method
- function sqlalchemy.orm.with_loader_criteria(entity_or_base: _EntityType[Any], where_criteria: _ColumnExpressionArgument[bool] | Callable[[Any], _ColumnExpressionArgument[bool]], loader_only: bool = False, include_aliases: bool = False, propagate_to_loaders: bool = True, track_closure_variables: bool = True) → LoaderCriteriaOption¶
为特定实体的所有出现次数的加载添加额外的 WHERE 条件。
1.4 版本新增。
with_loader_criteria()选项旨在为查询中的特定类型的实体添加限制条件,全局地,这意味着它将应用于实体在 SELECT 查询中以及任何子查询、连接条件和关系加载(包括迫切加载和延迟加载)中的出现,而无需在查询的任何特定部分中指定它。渲染逻辑使用与单表继承相同的系统,以确保将某个鉴别器应用于表。例如,使用 2.0 风格 的查询,我们可以限制加载
User.addresses集合的方式,无论使用何种加载方式from sqlalchemy.orm import with_loader_criteria stmt = select(User).options( selectinload(User.addresses), with_loader_criteria(Address, Address.email_address != "foo"), )
上面,
User.addresses的 “selectinload” 将给定的过滤条件应用于 WHERE 子句。另一个示例,其中过滤将应用于连接的 ON 子句,在此示例中使用 1.x 风格 的查询
q = ( session.query(User) .outerjoin(User.addresses) .options(with_loader_criteria(Address, Address.email_address != "foo")) )
with_loader_criteria()的主要目的是在SessionEvents.do_orm_execute()事件处理程序中使用它,以确保以某种方式过滤特定实体的所有出现,例如按访问控制角色进行过滤。它也可以用于将条件应用于关系加载。在下面的示例中,我们可以将一组特定的规则应用于特定Session发出的所有查询session = Session(bind=engine) @event.listens_for("do_orm_execute", session) def _add_filtering_criteria(execute_state): if ( execute_state.is_select and not execute_state.is_column_load and not execute_state.is_relationship_load ): execute_state.statement = execute_state.statement.options( with_loader_criteria( SecurityRole, lambda cls: cls.role.in_(["some_role"]), include_aliases=True, ) )
在上面的示例中,
SessionEvents.do_orm_execute()事件将拦截使用Session发出的所有查询。对于那些是 SELECT 语句且不是属性或关系加载的查询,自定义的with_loader_criteria()选项被添加到查询中。with_loader_criteria()选项将在给定的语句中使用,并且还将自动传播到从此查询派生的所有关系加载。给定的 criteria 参数是一个
lambda,它接受一个cls参数。给定的类将扩展为包括所有映射的子类,并且本身不必是映射的类。提示
当结合
contains_eager()加载器选项使用with_loader_criteria()选项时,重要的是要注意with_loader_criteria()仅影响查询中确定在 WHERE 和 FROM 子句方面渲染哪些 SQL 的部分。contains_eager()选项不影响 SELECT 语句在 columns 子句之外的渲染,因此与with_loader_criteria()选项没有任何交互。然而,“工作” 方式是contains_eager()旨在与已经以某种方式从附加实体中选择的查询一起使用,其中with_loader_criteria()可以应用其附加条件。在下面的示例中,假设映射关系为
A -> A.bs -> B,给定的with_loader_criteria()选项将影响 JOIN 的渲染方式stmt = ( select(A) .join(A.bs) .options(contains_eager(A.bs), with_loader_criteria(B, B.flag == 1)) )
上面,给定的
with_loader_criteria()选项将影响由.join(A.bs)指定的 JOIN 的 ON 子句,因此按预期应用。contains_eager()选项的效果是将B中的列添加到 columns 子句中SELECT b.id, b.a_id, b.data, b.flag, a.id AS id_1, a.data AS data_1 FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
在上述语句中使用
contains_eager()选项对with_loader_criteria()选项的行为没有影响。如果省略contains_eager()选项,则 SQL 在 FROM 和 WHERE 子句方面将是相同的,其中with_loader_criteria()继续将其条件添加到 JOIN 的 ON 子句中。contains_eager()的添加仅影响 columns 子句,因为添加了针对b的附加列,然后 ORM 使用这些列来生成B实例。警告
在调用
with_loader_criteria()内部使用 lambda 仅针对每个唯一类调用一次。自定义函数不应在此 lambda 中调用。有关 “lambda SQL” 功能的概述,请参阅 使用 Lambdas 为语句生成增加显著的速度增益,该功能仅供高级使用。- 参数:
entity_or_base¶ – 应用规则的映射类,或作为特定映射类集合的超类的类。
where_criteria¶ –
应用限制条件的核心 SQL 表达式。当给定的类是具有许多不同映射子类的基类时,这也可以是接受目标类作为参数的 “lambda:” 或 Python 函数。
注意
为了支持 pickle,请使用模块级的 Python 函数来生成 SQL 表达式,而不是 lambda 或固定的 SQL 表达式,因为它们往往不可 pickle。
propagate_to_loaders¶ –
默认为 True,应用于关系加载器,例如延迟加载器。这表示选项对象本身(包括 SQL 表达式)随每个加载的实例一起携带。设置为
False以防止对象被分配给单个实例。另请参阅
ORM 查询事件 - 包括使用
with_loader_criteria()的示例。添加全局 WHERE / ON 条件 - 关于如何将
with_loader_criteria()与SessionEvents.do_orm_execute()事件结合使用的基本示例。track_closure_variables¶ –
当为 False 时,lambda 表达式内部的闭包变量将不作为任何缓存键的一部分使用。这允许在 lambda 表达式内部使用更复杂的表达式,但要求 lambda 确保每次给定特定类时都返回相同的 SQL。
1.4.0b2 版本新增。
- function sqlalchemy.orm.join(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, isouter: bool = False, full: bool = False) → _ORMJoin¶
在 left 和 right 子句之间生成内连接。
join()是对join()提供的核心 join 接口的扩展,其中 left 和 right selectable 不仅可以是核心 selectable 对象(例如Table),还可以是映射类或AliasedClass实例。“on” 子句可以是 SQL 表达式或引用配置的relationship()的 ORM 映射属性。在现代用法中,通常不需要
join(),因为它的功能封装在Select.join()和Query.join()方法中,这些方法的功能远超join()本身所能提供的自动化程度。显式使用join()和启用 ORM 的 SELECT 语句涉及使用Select.select_from()方法,如下所示from sqlalchemy.orm import join stmt = ( select(User) .select_from(join(User, Address, User.addresses)) .filter(Address.email_address == "foo@bar.com") )
在现代 SQLAlchemy 中,上面的 join 可以更简洁地写成
stmt = ( select(User) .join(User.addresses) .filter(Address.email_address == "foo@bar.com") )
警告
直接使用
join()可能无法与现代 ORM 选项(例如with_loader_criteria())正常工作。强烈建议在使用 ORM 连接时使用由Select.join()和Select.join_from()等方法提供的惯用 join 模式。
- function sqlalchemy.orm.outerjoin(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, full: bool = False) → _ORMJoin¶
在 left 和 right 子句之间生成左外连接。
这是
join()函数的 “外连接” 版本,具有相同的行为,只是生成 OUTER JOIN。有关其他用法详细信息,请参阅该函数的文档。
- function sqlalchemy.orm.with_parent(instance: object, prop: attributes.QueryableAttribute[Any], from_entity: _EntityType[Any] | None = None) → ColumnElement[bool]¶
创建过滤条件,使用已建立的
relationship()配置,将此查询的主实体与给定的相关实例关联起来。例如:
stmt = select(Address).where(with_parent(some_user, User.addresses))渲染的 SQL 与从该属性上的给定父级触发延迟加载器时渲染的 SQL 相同,这意味着从 Python 中的父对象获取适当的状态,而无需在渲染的语句中渲染到父表的连接。
给定的 property 也可以使用
PropComparator.of_type()来指示条件的左侧a1 = aliased(Address) a2 = aliased(Address) stmt = select(a1, a2).where(with_parent(u1, User.addresses.of_type(a2)))
上面的用法等效于使用
from_entity()参数a1 = aliased(Address) a2 = aliased(Address) stmt = select(a1, a2).where( with_parent(u1, User.addresses, from_entity=a2) )
- 参数:
instance¶ – 具有某些
relationship()的实例。property¶ – 类绑定的属性,指示应使用实例中的哪个关系来协调父/子关系。
from_entity¶ –
要考虑作为左侧的实体。这默认为
Query本身的 “零” 实体。1.2 版本新增。
flambé! 龙和 The Alchemist 图像设计由 Rotem Yaari 创作并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档上次生成时间:Tue 11 Mar 2025 02:40:17 PM EDT