用于查询的 ORM API 功能¶
ORM Loader 选项¶
Loader 选项是当传递给
Select.options()
方法或类似的 SQL 结构会影响列和面向关系的属性的加载。大多数加载器选项都从
Load
等级制度。有关使用 loader 选项的完整概述,请参阅链接的
部分。
另请参阅
列加载选项 - 详细说明影响列和 SQL 表达式映射属性加载方式的映射器和加载选项
关系加载技术 - 详细说明影响relationship()
映射属性加载方式的关系和加载选项
ORM 执行选项¶
ORM 级别的执行选项是可能与
语句执行
Session.execute.execution_options
parameter 的 Json 参数,它是 Session
方法接受的字典参数,例如
Session.execute()
和 Session.scalars() 的 Session.scales()
和
将它们直接与要调用的语句本身相关联,使用
Executable.execution_options()
方法,该方法接受它们作为任意关键字参数。
ORM 级别的选项与 中 Connection.execution_options()
记录的核心级别执行选项不同。需要注意的是,下面讨论的 ORM 选项与 Core 级别方法不兼容
Connection.execution_options()
或
Engine.execution_options()
;在此级别,即使 Engine
或 Connection
与正在使用的 Session
关联,也会忽略这些选项。
在本节中,将对 Executable.execution_options()
方法样式进行说明。
填充现有¶
populate_existing
execution 选项可确保对于加载的所有行,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()
方法。
自动刷新¶
当作为 False
传递时,此选项将导致 Session
不调用 “autoflush” 步骤。 它相当于使用
Session.no_autoflush
Context Manager 禁用 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
和
删除
查询。
autoflush
执行选项等同于
Query.autoflush()
方法。
另请参阅
使用 Yield Per 获取大型结果集¶
yield_per
执行选项是一个整数值,这将导致
Result
一次只缓冲有限数量的行和/或 ORM 对象,然后再将数据提供给 Client 端。
通常,ORM 将立即获取所有行,为每个行构建 ORM 对象并将这些对象组装到单个缓冲区中,然后将此缓冲区作为要返回的行的源传递给 Result
对象。此行为的基本原理是允许对功能进行正确的行为,例如联接预先加载、结果单一化,以及结果处理逻辑的一般情况,该逻辑依赖于身份映射在获取结果时为结果集中的每个对象保持一致的状态。
yield_per
选项的目的是更改此行为,以便 ORM 结果集针对非常大的结果集(例如 > 10K 行)进行迭代,其中用户已确定上述模式不适用。当使用 yield_per
时,ORM 会将 ORM 结果批处理到
sub-collections 并单独从每个 sub-collection 中生成行作为
Result
对象,因此 Python 解释器不需要声明非常大的内存区域,这既耗时又会导致内存使用过多。该选项既影响数据库游标的使用方式,也影响 ORM 构造要传递给 Result
的行和对象的方式。
提示
从上面可以看出,Result
必须是
以可迭代的方式使用,即使用 Iteration,例如
for row 或使用
部分行方法(如
Result.fetchmany()
或 Result.partitions() 的 Result.partitions()
进行。调用 Result.all()
将违背使用
yield_per
。
使用 yield_per
等效于同时使用 Connection.execution_options.stream_results
execution 选项,用于选择要使用的服务器端游标
如果支持,则通过后端,以及返回的 Result
对象上的 Result.yield_per()
方法,该方法建立了要获取的固定行大小以及一次构建多少 ORM 对象的相应限制。
提示
yield_per
现在也作为 Core 执行选项提供,使用 Server Side Cursors (a.k.a. stream results) 中有详细介绍。本节详细介绍了如何使用 yield_per
作为 ORM 的执行选项
会话
。该选项在两种上下文中的行为尽可能相似。
当与 ORM 一起使用时,yield_per必须
通过给定语句上的 Executable.execution_options()
方法或将其 Session.execute.execution_options
传递给
parameter
或其他类似的 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
Core 级别的执行选项与 Result.yield_per()
结合使用
Method 的 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
执行选项与
“subquery” 急切加载 loading 或
“joined” 预先加载。它可能与 “select in” eager loading 兼容,前提是数据库驱动程序支持多个独立的游标。
此外,yield_per
执行选项与 Result.unique()
方法不兼容;由于此方法依赖于存储所有行的完整标识集,因此它必然会破坏使用 yield_per
的目的,即处理任意数量的行。
在 1.4.6 版本发生变更: 当从使用
Result.unique()
过滤器,同时yield_per
execution 选项。
当将旧版 Query
对象与
1.x 样式ORM 使用时,Query.yield_per()
方法将具有与 yield_per
执行选项相同的结果。
另请参阅
身份令牌¶
深度炼金术
此选项是一项高级用途功能,主要用于 Horizontal Sharding 扩展。对于从不同的 “分片” 或分区加载具有相同主键的对象的典型情况,请考虑使用单独的 Session
objects per shard (每个分片) 的对象数。
“身份令牌” 是一个任意值,可以在新加载的对象的身份密钥中关联。 此元素存在
首先,也是最重要的一点是支持执行每行 “分片” 的扩展,
其中,对象可以从特定
数据库表,但具有重叠的主键值。
“身份令牌” 的主要使用者是
水平分片扩展,它提供了一个通用框架,用于在特定数据库表的多个 “分片” 之间持久保存对象。
identity_token
execution 选项可以基于每个查询使用
直接影响此 Token。 直接使用它,可以填充一个
具有相同主键和源表但 “身份” 不同的对象的多个实例的会话
。
一个这样的例子是用 Session
填充
来自不同架构中的同名表,使用
Translation of Schema Names 功能,可影响查询范围内架构的选择。给定一个映射为:
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
,这意味着不会将 schema 限定写入 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
对象是独立的。 如果我们想要
将两个对象持久化在一个事务中,我们需要使用
Horizontal Sharding 扩展来执行此作。
但是,我们可以在一个会话中说明对这些对象的查询,如下所示:
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
类的主键 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 版本的新Function: - 添加了 identity_token
ORM 级别执行选项。
另请参阅
水平分片 - 在 ORM Examples 部分中。请参阅脚本separate_schema_translates.py
,了解使用完整分片 API 的上述用例的演示。
检查启用 ORM 的 SELECT 和 DML 语句中的实体和列¶
select()
结构,以及 insert()
的 update()
和 delete()
结构(对于后者的 DML 结构,从 SQLAlchemy 1.4.33 开始),都支持检查创建这些语句所针对的实体的能力,以及将在结果集中返回的列和数据类型。
对于 Select
对象,此信息可从
Select.column_descriptions
属性。此属性的运行方式与 legacy 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”
实际上是要插入、更新的 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 结构¶
对象名称 |
描述 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
函数 sqlalchemy.orm 中。aliased(element:_EntityType[_O]FromClause, alias:FromClauseNone=None, name:strNone=None, flat: bool = False, adapt_on_names: bool = False)→AliasedClass[_O]FromClauseAliasedType[_O]¶
生成给定元素的别名,通常是AliasedClass
实例。
例如:my_alias = aliased(MyClass) stmt = select(MyClass, my_alias).filter(MyClass.id > my_alias.id) result = session.execute(stmt)
aliased()
函数用于创建映射类到新可选对象的临时映射。默认情况下,一个 selectable 是从正常映射的 selectable(通常是一个Table
) 使用FromClause.alias()
方法。但是,aliased()
也可以是 用于将类链接到新的select()
语句。此外,with_polymorphic()
函数是aliased()
用于指定所谓的“多态可选”,它对应于同时对应于多个连接继承子类的并集。
为方便起见,aliased()
函数也接受 plainFromClause
结构,例如Table
或select()
结构。 在这些情况下,FromClause.alias()
method 在对象上调用,并且新的返回 Alias
对象。 返回的 在这种情况下,别名
不是 ORM 映射的。
参数
element¶ – 要别名的元素。通常是一个映射类,但为了方便起见,也可以是FromClause
元素。
alias¶- 要将元素映射到的可选单位。 这是 通常用于将对象链接到子查询,并且应该是别名 select 构造,就像从Query.subquery()
方法或Select.subquery()
或select()
的Select.alias()
方法 构建。
name¶ – 用于别名的可选字符串名称,如果alias
参数未指定。 除其他外,该名称构成了 attribute name 访问,该名称可通过Query
对象。创建Join
对象的别名时不受支持。flat¶ –
Boolean 的 Boolean 将被传递到FromClause.alias()
调用,以便Join
对象将为 Join 中的各个表设置别名,而不是创建子查询。所有现代数据库通常都支持右嵌套联接,并且通常会产生更高效的查询。
当aliased.flat
与aliased.name
,生成的联接将使用类似于<prefix>_<tablename>
的命名方案为各个表设置别名。此命名方案仅用于可见性/调试目的,具体方案如有更改,恕不另行通知。
2.0.32 版中的新功能:添加了对组合的支持aliased.name
aliased.flat
中。以前,这会引发NotImplementedError
。adapt_on_names¶ –
如果为 True,则在将 ORM 实体的映射列映射到给定可选对象的列时,将使用更自由的“匹配” - 如果给定的可选对象没有与实体上的列相对应的列,则将执行基于名称的匹配。这种情况的用例是将实体与一些派生的 selectable(例如使用聚合函数的 optionalable)相关联: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
列,因为它不是原始列的代理。
-
类 sqlalchemy.orm.util 中。别名类¶
表示映射类的“别名”形式,用于 Query。alias()
的 ORM 等价物 构造,此对象使用__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
还能够将现有的 Map 类映射到一个全新的 selectable,前提是这个 selectable 与现有的 mapped selectable 是列兼容的,并且它也可以在 mapping 中配置为relationship()
的目标。有关示例,请参阅下面的链接。AliasedClass
对象通常使用aliased()
函数。在使用with_polymorphic()
函数时,它也是通过额外的配置生成的。
生成的对象是AliasedClass
的实例。此对象实现一个属性方案,该方案生成与原始映射类相同的属性和方法接口,从而允许AliasedClass
与适用于原始类的任何属性技术兼容,包括混合属性(请参见混合属性)。
可以检查AliasedClass
的底层Mapper
、aliased selectable 和其他信息使用inspect():
from sqlalchemy import inspect my_alias = aliased(MyClass) insp = inspect(my_alias)
生成的检查对象是AliasedInsp
的实例。
类签名
类sqlalchemy.orm.AliasedClass
(sqlalchemy.inspection.Inspectable
,sqlalchemy.orm.ORMColumnsClauseRole
)
-
类 sqlalchemy.orm.util 中。别名Insp¶
为AliasedClass
对象。
在给定AliasedClass
的情况下,使用inspect()
函数: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
的集合 对象 指示 select 构造中表示的所有映射器 对于AliasedClass
。polymorphic_on
- 将用作多态加载的“鉴别器”的备用列或 SQL 表达式。
另请参阅
类签名
classsqlalchemy.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.通用
)
-
类 sqlalchemy.orm 中。捆绑¶ Query
返回的一组 SQL 表达式 在一个命名空间下。Bundle
实质上允许嵌套面向列的Query
对象返回的基于元组的结果。它也可以通过简单的子类化进行扩展,其中覆盖的主要功能是应如何返回表达式集,允许后处理以及自定义返回类型,而不涉及 ORM 身份映射类。
另请参阅
成员
__init__()、c、列、create_row_processor()、is_aliased_class、is_bundle、is_clause_element、is_mapper、label() single_entity
类签名
类sqlalchemy.orm.Bundle
(sqlalchemy.orm.ORMColumnsClauseRole
,sqlalchemy.sql.annotation.SupportsCloneAnnotations
,sqlalchemy.sql.cache_key.MemoizedHasCacheKey
sqlalchemy.inspection.Inspectable
sqlalchemy.orm.base.InspectionAttr
)-
方法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)
-
属性sqlalchemy.orm.Bundle 的
c: ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]¶ Bundle.columns
的别名。
-
属性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)
另请参阅
-
方法sqlalchemy.orm.Bundle 中。
create_row_processor(query: Select[Any], procs: Sequence[Callable[[Row[Any]], Any]], labels: Sequence[str])Callable[[行[任意]],任意] ¶
为此Bundle
生成 “row processing” 函数。
可以被子类覆盖,以便在获取结果时提供自定义行为。该方法在查询执行时传递 statement 对象和一组“row processor”函数;当给定 result 行时,这些处理器函数将返回单个属性值,然后可以将其调整为任何类型的 return 数据结构。
下面的示例说明了如何替换通常的Row
return 结构: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"])
-
属性sqlalchemy.orm.Bundle 的
is_aliased_class = False¶
如果此对象是AliasedClass
的实例,则为 True。
-
属性sqlalchemy.orm.Bundle 的
is_bundle = 真¶
如果此对象是Bundle
的实例,则为 True。
-
属性sqlalchemy.orm.Bundle 的
is_clause_element = False¶
如果此对象是ClauseElement 的 ClauseElement
。
-
属性sqlalchemy.orm.Bundle 的
is_mapper = False¶
如果此对象是Mapper
的实例,则为 True。
-
方法sqlalchemy.orm.Bundle 中。
label(name)¶
提供此捆绑包
的副本,并传递新标签。
-
属性sqlalchemy.orm.Bundle 的
single_entity = False¶
如果为 True,则对单个 Bundle 的查询将作为单个实体返回,而不是键控元组中的元素。
-
-
函数 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()
选项旨在添加 将条件限制为查询中特定类型的实体, globally,这意味着它将应用于实体,因为它出现在 SELECT 查询中以及任何子查询、联接条件和关系加载中,包括 Eager 和 Lazy 加载器,而无需在查询的任何特定部分中指定它。渲染逻辑使用与单个表继承相同的系统,以确保将某个鉴别器应用于表。
例如,使用 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()
事件将拦截使用会话
。对于作为 SELECT 语句的查询 和 not 属性或关系加载自定义with_loader_criteria()
选项已添加到查询中。 这with_loader_criteria()
选项将在给定语句中使用,并且还会自动传播到从此查询下降的所有关系加载。
给出的 criteria 参数是接受cls
的lambda
论点。 给定的类将扩展为包含所有映射的子类 并且本身不需要是一个映射的类。
提示
当with_loader_criteria()
选项与contains_eager()
加载器选项结合使用时,请务必注意仅with_loader_criteria()
影响确定呈现哪些 SQL 的查询部分 在 WHERE 和 FROM 子句方面。这contains_eager()
选项不会影响 columns 子句之外的 SELECT 语句的呈现,因此与with_loader_criteria()
选项没有任何交互。然而,事情的 “运作 ”方式是contains_eager()
用于已从 additional entities 中,其中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)
中,因此会按预期应用。这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 SQL”功能的概述,请参阅使用 Lambda 显著提高语句生成速度,该功能仅供高级使用。
参数
entity_or_base¶– 一个映射类,或者一个类,它是一组特定的映射类的超类,规则将应用于该类。where_criteria¶ –
应用限制条件的 Core SQL 表达式。当给定类是具有许多不同映射子类的基类时,这也可以是接受目标类作为参数的 “lambda:” 或 Python 函数。
注意
要支持封存,请使用模块级 Python 函数生成 SQL 表达式,而不是 lambda 或固定的 SQL 表达式,后者往往不可封存。propagate_to_loaders¶ –
默认为 True,则应用于关系加载器,例如延迟加载器。这表示 option 对象本身(包括 SQL 表达式)与每个加载的实例一起携带。设置为False
可防止将对象分配给单个实例。
另请参阅
ORM Query Events - 包括使用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:_OnClauseArgumentNone=None, isouter: bool = False, full: bool = False)_ORMJoin ¶
在 left 子句和 right 子句之间生成内部联接。join()
是join()
提供的核心连接接口的扩展,其中左右可选不仅可以是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 中,上述连接可以更简洁地写成:stmt = ( select(User) .join(User.addresses) .filter(Address.email_address == "foo@bar.com") )
警告
直接使用join()
可能无法与现代 ORM 选项(如with_loader_criteria() )
一起正常工作。强烈建议使用Select.join()
和Select.join_from()
创建 ORM 连接时。
-
函数 sqlalchemy.orm 中。outerjoin(left: _FromClauseArgument, right: _FromClauseArgument, onclause:_OnClauseArgumentNone=None, full: bool = False)_ORMJoin ¶
在 left 子句和 right 子句之间生成 left outer join。
这是join()
函数的 “outer join” 版本,除了生成 OUTER JOIN 外,具有相同的行为。有关其他使用详情,请参阅该函数的文档。
-
函数 sqlalchemy.orm 中。with_parent(instance: object, prop: attributes.QueryableAttribute[Any], from_entity:_EntityType[Any]None=None)ColumnElement[bool] ¶
创建与此查询的主实体相关的筛选条件 到给定的相关实例,使用 established关系()
配置。
例如:stmt = select(Address).where(with_parent(some_user, User.addresses))
渲染的 SQL 与惰性加载器从该属性上的给定父级触发时渲染的 SQL 相同,这意味着适当的状态是从 Python 中的父对象获取的,而无需在渲染的语句中渲染到父表的连接。
给定的属性也可以使用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 版本加入.