用于查询的 ORM API 功能


ORM Loader 选项


Loader 选项是当传递给 Select.options() 方法或类似的 SQL 结构会影响列和面向关系的属性的加载。大多数加载器选项都从 Load 等级制度。有关使用 loader 选项的完整概述,请参阅链接的 部分。


另请参阅


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();在此级别,即使 EngineConnection 与正在使用的 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 的另一个用例是支持各种属性加载功能,这些功能可以更改每个查询的属性加载方式。适用的选项包括:


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_tabletest_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",
        )
    )


obj1obj2 彼此不同。但是,它们都引用 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 对象(例如普通 TableColumn 对象)一起使用时,这些条目将包含有关在所有情况下返回的单个列的基本信息:

>>> 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 结构


对象名称

描述


aliased(元素[, 别名, 名称, 平面, ...])


生成给定元素的别名,通常是 AliasedClass 实例。


别名类


表示映射类的“别名”形式,用于 Query。


别名Insp


AliasedClass 对象。



Query 返回的一组 SQL 表达式 在一个命名空间下。


join(left, right[, onclause, isouter, ...])


在 left 子句和 right 子句之间生成内部联接。


outerjoin(left, right[, on子句, full])


在 left 子句和 right 子句之间生成 left outer join。


with_loader_criteria(entity_or_base, where_criteria[, loader_only, include_aliases, ...])


为特定实体的所有实例向加载添加其他 WHERE 条件。


with_parent(instance, prop[, from_entity])


创建与此查询的主实体相关的筛选条件 到给定的相关实例,使用 established 关系() 配置。


函数 sqlalchemy.orm 中。aliasedelement:_EntityType[_O]FromClause, alias:FromClauseNone=None, name:strNone=None, flat bool = Falseadapt_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() 函数也接受 plain FromClause 结构,例如 Tableselect() 结构。 在这些情况下, 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.flataliased.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.AliasedClasssqlalchemy.inspection.Inspectablesqlalchemy.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


  • selectable - 别名 构建最终 表示别名 Table选择 构建。


  • name - 别名的名称。在 Query 的结果元组中返回时,也用作属性名称。


  • with_polymorphic_mappers - Mapper 的集合 对象 指示 select 构造中表示的所有映射器 对于 AliasedClass


  • polymorphic_on - 将用作多态加载的“鉴别器”的备用列或 SQL 表达式。


另请参阅


运行时检查 API


类签名


class sqlalchemy.orm.AliasedInspsqlalchemy.orm.ORMEntityColumnsClauseRolesqlalchemy.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 身份映射类。


类签名


sqlalchemy.orm.Bundlesqlalchemy.orm.ORMColumnsClauseRolesqlalchemy.sql.annotation.SupportsCloneAnnotationssqlalchemy.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)

参数

  • name- 捆绑包的名称。


  • exprs —— 组成 bundle 的列或 SQL 表达式。


  • single_entity=False – 如果为 True,则此 Bundle 的行 可以作为任何封闭元组之外的 “单个实体” 返回 方式与映射实体相同。


属性 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)


另请参阅


捆绑.c


方法 sqlalchemy.orm.Bundle 中。create_row_processorquery 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 中。labelname


提供此捆绑包的副本,并传递新标签。


属性 sqlalchemy.orm.Bundle 的 single_entity = False


如果为 True,则对单个 Bundle 的查询将作为单个实体返回,而不是键控元组中的元素。


函数 sqlalchemy.orm 中。with_loader_criteriaentity_or_base _EntityType[Any], where_criteria:_ColumnExpressionArgument[bool]Callable[[Any],_ColumnExpressionArgument[bool]], loader_only: bool =Falseinclude_aliases: bool = Falsepropagate_to_loaders: bool = Truetrack_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 参数是接受 clslambda 论点。 给定的类将扩展为包含所有映射的子类 并且本身不需要是一个映射的类。


提示


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 表达式,后者往往不可封存。


  • include_aliases – 如果为 True,则将规则应用于 aliased() 构造体。

  • propagate_to_loaders


    默认为 True,则应用于关系加载器,例如延迟加载器。这表示 option 对象本身(包括 SQL 表达式)与每个加载的实例一起携带。设置为 False 可防止将对象分配给单个实例。

  • track_closure_variables


    当 False 时,lambda 表达式内的闭包变量将不会用作任何缓存键的一部分。这允许在 lambda 表达式中使用更复杂的表达式,但要求 lambda 确保每次给定特定类时都返回相同的 SQL。


    1.4.0b2 版本的新Function。


函数 sqlalchemy.orm 中。joinleft _FromClauseArgumentright _FromClauseArgument, onclause:_OnClauseArgumentNone=None, isouter bool = Falsefull 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 连接时。


另请参阅


连接 - 在 ORM 查询指南中,了解惯用的 ORM 连接模式的背景


函数 sqlalchemy.orm 中。outerjoinleft _FromClauseArgumentright _FromClauseArgument, onclause:_OnClauseArgumentNone=None, full bool = False _ORMJoin


在 left 子句和 right 子句之间生成 left outer join。


这是 join() 函数的 “outer join” 版本,除了生成 OUTER JOIN 外,具有相同的行为。有关其他使用详情,请参阅该函数的文档。


函数 sqlalchemy.orm 中。with_parentinstance objectprop 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 版本加入.