SqlAlchemy 2.0 中文文档(十六)(1)https://developer.aliyun.com/article/1562941
使用 with_polymorphic() 过滤子类属性
with_polymorphic()
构造使包含的子类映射器上的属性可用,通过包含允许对子类的引用的命名空间。在前一节中创建的 employee_poly
构造包括名为 .Engineer
和 .Manager
的属性,这些属性为 Engineer
和 Manager
提供了关于多态 SELECT 的命名空间。在下面的示例中,我们可以使用 or_()
构造同时针对两个类创建条件:
>>> from sqlalchemy import or_ >>> employee_poly = with_polymorphic(Employee, [Engineer, Manager]) >>> stmt = ( ... select(employee_poly) ... .where( ... or_( ... employee_poly.Manager.manager_name == "Eugene H. Krabs", ... employee_poly.Engineer.engineer_info ... == "Senior Customer Engagement Engineer", ... ) ... ) ... .order_by(employee_poly.id) ... ) >>> objects = session.scalars(stmt).all() SELECT employee.id, employee.name, employee.type, employee.company_id, manager.id AS id_1, manager.manager_name, engineer.id AS id_2, engineer.engineer_info FROM employee LEFT OUTER JOIN manager ON employee.id = manager.id LEFT OUTER JOIN engineer ON employee.id = engineer.id WHERE manager.manager_name = ? OR engineer.engineer_info = ? ORDER BY employee.id [...] ('Eugene H. Krabs', 'Senior Customer Engagement Engineer') >>> print(objects) [Manager('Mr. Krabs'), Engineer('Squidward')] ```### 使用别名化与 with_polymorphic `with_polymorphic()` 构造,作为 `aliased()` 的特例,也提供了 `aliased()` 的基本功能,即对多态可选择本身的“别名化”。具体来说,这意味着两个或更多个引用相同类层次结构的 `with_polymorphic()` 实体可以同时在单个语句中使用。 要在连接继承映射中使用此功能,通常我们希望传递两个参数,`with_polymorphic.aliased` 以及 `with_polymorphic.flat`。`with_polymorphic.aliased` 参数表示多态可选择应该由此构造唯一的别名引用。`with_polymorphic.flat` 参数是特定于默认的 LEFT OUTER JOIN 多态可选择,并指示语句中应使用更优化的别名化形式。 为了说明这个特性,下面的示例发出了一个选择两个单独的多态实体,`Employee` 与 `Engineer` 连接,以及 `Employee` 与 `Manager` 连接的 SELECT。由于这两个多态实体都将在其多态可选择中包含基本的 `employee` 表,必须应用别名以区分这个表在其两个不同的上下文中。这两个多态实体被视为两个独立的表,因此通常需要以某种方式相互连接,如下所示,在这里实体在 `company_id` 列上与彼此连接,并附加一些额外的限制条件针对 `Employee` / `Manager` 实体: ```py >>> manager_employee = with_polymorphic(Employee, [Manager], aliased=True, flat=True) >>> engineer_employee = with_polymorphic(Employee, [Engineer], aliased=True, flat=True) >>> stmt = ( ... select(manager_employee, engineer_employee) ... .join( ... engineer_employee, ... engineer_employee.company_id == manager_employee.company_id, ... ) ... .where( ... or_( ... manager_employee.name == "Mr. Krabs", ... manager_employee.Manager.manager_name == "Eugene H. Krabs", ... ) ... ) ... .order_by(engineer_employee.name, manager_employee.name) ... ) >>> for manager, engineer in session.execute(stmt): ... print(f"{manager} {engineer}") SELECT employee_1.id, employee_1.name, employee_1.type, employee_1.company_id, manager_1.id AS id_1, manager_1.manager_name, employee_2.id AS id_2, employee_2.name AS name_1, employee_2.type AS type_1, employee_2.company_id AS company_id_1, engineer_1.id AS id_3, engineer_1.engineer_info FROM employee AS employee_1 LEFT OUTER JOIN manager AS manager_1 ON employee_1.id = manager_1.id JOIN (employee AS employee_2 LEFT OUTER JOIN engineer AS engineer_1 ON employee_2.id = engineer_1.id) ON employee_2.company_id = employee_1.company_id WHERE employee_1.name = ? OR manager_1.manager_name = ? ORDER BY employee_2.name, employee_1.name [...] ('Mr. Krabs', 'Eugene H. Krabs') Manager('Mr. Krabs') Manager('Mr. Krabs') Manager('Mr. Krabs') Engineer('SpongeBob') Manager('Mr. Krabs') Engineer('Squidward')
在上面的例子中,with_polymorphic.flat
的行为是,多态可选项保持为其各自表的 LEFT OUTER JOIN,这些表本身被赋予匿名别名。还生成了一个右嵌套 JOIN。
当省略with_polymorphic.flat
参数时,通常行为是每个多态可选项都被包含在子查询中,产生更加冗长的形式:
>>> manager_employee = with_polymorphic(Employee, [Manager], aliased=True) >>> engineer_employee = with_polymorphic(Employee, [Engineer], aliased=True) >>> stmt = ( ... select(manager_employee, engineer_employee) ... .join( ... engineer_employee, ... engineer_employee.company_id == manager_employee.company_id, ... ) ... .where( ... or_( ... manager_employee.name == "Mr. Krabs", ... manager_employee.Manager.manager_name == "Eugene H. Krabs", ... ) ... ) ... .order_by(engineer_employee.name, manager_employee.name) ... ) >>> print(stmt) SELECT anon_1.employee_id, anon_1.employee_name, anon_1.employee_type, anon_1.employee_company_id, anon_1.manager_id, anon_1.manager_manager_name, anon_2.employee_id AS employee_id_1, anon_2.employee_name AS employee_name_1, anon_2.employee_type AS employee_type_1, anon_2.employee_company_id AS employee_company_id_1, anon_2.engineer_id, anon_2.engineer_engineer_info FROM (SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, employee.company_id AS employee_company_id, manager.id AS manager_id, manager.manager_name AS manager_manager_name FROM employee LEFT OUTER JOIN manager ON employee.id = manager.id) AS anon_1 JOIN (SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, employee.company_id AS employee_company_id, engineer.id AS engineer_id, engineer.engineer_info AS engineer_engineer_info FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id) AS anon_2 ON anon_2.employee_company_id = anon_1.employee_company_id WHERE anon_1.employee_name = :employee_name_2 OR anon_1.manager_manager_name = :manager_manager_name_1 ORDER BY anon_2.employee_name, anon_1.employee_name
上述形式在历史上更容易移植到不一定支持右嵌套 JOIN 的后端,并且在使用诸如具体表继承映射以及一般情况下使用替代多态可选项时,可能也是合适的。 ### 在映射上配置 with_polymorphic()
与 selectin_polymorphic()
类似,with_polymorphic()
构造也支持一个经过映射配置的版本,可以通过两种不同的方式进行配置,要么在基类上使用 mapper.with_polymorphic
参数,要么以更现代的形式在每个子类上使用 Mapper.polymorphic_load
参数,传递值为 "inline"
。
警告
对于加入继承映射,更倾向于在查询中明确使用 with_polymorphic()
,或者对于隐式的子类急加载使用 Mapper.polymorphic_load
以 "selectin"
为参数,而不是使用本节中描述的映射级别的 mapper.with_polymorphic
参数。该参数调用了旨在重写 SELECT 语句中的 FROM 子句的复杂启发式规则,可能会干扰更复杂语句的构建,尤其是那些涉及到引用同一映射实体的嵌套子查询的语句。
例如,我们可以使用以下方式声明我们的 Employee
映射,将 Mapper.polymorphic_load
设为 "inline"
:
class Employee(Base): __tablename__ = "employee" id = mapped_column(Integer, primary_key=True) name = mapped_column(String(50)) type = mapped_column(String(50)) __mapper_args__ = {"polymorphic_identity": "employee", "polymorphic_on": type} class Engineer(Employee): __tablename__ = "engineer" id = mapped_column(Integer, ForeignKey("employee.id"), primary_key=True) engineer_info = mapped_column(String(30)) __mapper_args__ = { "polymorphic_load": "inline", "polymorphic_identity": "engineer", } class Manager(Employee): __tablename__ = "manager" id = mapped_column(Integer, ForeignKey("employee.id"), primary_key=True) manager_name = mapped_column(String(30)) __mapper_args__ = { "polymorphic_load": "inline", "polymorphic_identity": "manager", }
对于上述映射,针对 Employee
类的 SELECT 语句将自动假设在发出语句时使用 with_polymorphic(Employee, [Engineer, Manager])
作为主要实体:
print(select(Employee)) SELECT employee.id, employee.name, employee.type, engineer.id AS id_1, engineer.engineer_info, manager.id AS id_2, manager.manager_name FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id LEFT OUTER JOIN manager ON employee.id = manager.id
当使用映射器级“with polymorphic”时,查询也可以直接引用子类实体,其中它们隐式地表示多态查询中的连接表。在上面的例子中,我们可以自由地直接引用 Manager
和 Engineer
对默认的 Employee
实体进行查询:
print( select(Employee).where( or_(Manager.manager_name == "x", Engineer.engineer_info == "y") ) ) SELECT employee.id, employee.name, employee.type, engineer.id AS id_1, engineer.engineer_info, manager.id AS id_2, manager.manager_name FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id LEFT OUTER JOIN manager ON employee.id = manager.id WHERE manager.manager_name = :manager_name_1 OR engineer.engineer_info = :engineer_info_1
然而,如果我们需要在单独的别名上下文中引用 Employee
实体或其子实体,我们将再次直接使用 with_polymorphic()
来定义这些别名实体,如 使用别名与 with_polymorphic 中所示。
对于对多态可选的更集中的控制,可以使用更传统的映射器级多态控制形式,即 Mapper.with_polymorphic
参数,配置在基类上。此参数接受与 with_polymorphic()
构造相当的参数,然而,在连接继承映射中的常见用法是使用普通的星号,表示所有子表都应该进行 LEFT OUTER JOIN,如下所示:
class Employee(Base): __tablename__ = "employee" id = mapped_column(Integer, primary_key=True) name = mapped_column(String(50)) type = mapped_column(String(50)) __mapper_args__ = { "polymorphic_identity": "employee", "with_polymorphic": "*", "polymorphic_on": type, } class Engineer(Employee): __tablename__ = "engineer" id = mapped_column(Integer, ForeignKey("employee.id"), primary_key=True) engineer_info = mapped_column(String(30)) __mapper_args__ = { "polymorphic_identity": "engineer", } class Manager(Employee): __tablename__ = "manager" id = mapped_column(Integer, ForeignKey("employee.id"), primary_key=True) manager_name = mapped_column(String(30)) __mapper_args__ = { "polymorphic_identity": "manager", }
总的来说,with_polymorphic()
和诸如 Mapper.with_polymorphic
这样的选项使用的 LEFT OUTER JOIN 格式可能从 SQL 和数据库优化器的角度来看会比较繁琐;对于连接继承映射中子类属性的一般加载,应该更倾向于使用 selectin_polymorphic()
方法,或者将 Mapper.polymorphic_load
设置为 "selectin"
的映射器级等效,只在需要时才在每个查询基础上使用 with_polymorphic()
。 ## 加入到特定子类型或 with_polymorphic() 实体
由于with_polymorphic()
实体是aliased()
的一种特殊情况,在将多态实体视为连接的目标时,特别是在使用relationship()
构造作为 ON 子句时,我们使用与常规别名相同的技术,如在 Using Relationship to join between aliased targets 中详细说明的,最简洁的方式是使用PropComparator.of_type()
。在下面的示例中,我们演示了从父实体Company
沿着一对多关系Company.employees
进行连接,该关系在 setup 中配置为链接到Employee
对象,使用一个with_polymorphic()
实体作为目标:
>>> employee_plus_engineer = with_polymorphic(Employee, [Engineer]) >>> stmt = ( ... select(Company.name, employee_plus_engineer.name) ... .join(Company.employees.of_type(employee_plus_engineer)) ... .where( ... or_( ... employee_plus_engineer.name == "SpongeBob", ... employee_plus_engineer.Engineer.engineer_info ... == "Senior Customer Engagement Engineer", ... ) ... ) ... ) >>> for company_name, emp_name in session.execute(stmt): ... print(f"{company_name} {emp_name}") SELECT company.name, employee.name AS name_1 FROM company JOIN (employee LEFT OUTER JOIN engineer ON employee.id = engineer.id) ON company.id = employee.company_id WHERE employee.name = ? OR engineer.engineer_info = ? [...] ('SpongeBob', 'Senior Customer Engagement Engineer') Krusty Krab SpongeBob Krusty Krab Squidward
更直接地说,PropComparator.of_type()
也与任何类型的继承映射一起使用,以将一个relationship()
的连接限制为特定的子类型。上面的查询可以严格按照Engineer
目标来编写,如下所示:
>>> stmt = ( ... select(Company.name, Engineer.name) ... .join(Company.employees.of_type(Engineer)) ... .where( ... or_( ... Engineer.name == "SpongeBob", ... Engineer.engineer_info == "Senior Customer Engagement Engineer", ... ) ... ) ... ) >>> for company_name, emp_name in session.execute(stmt): ... print(f"{company_name} {emp_name}") SELECT company.name, employee.name AS name_1 FROM company JOIN (employee JOIN engineer ON employee.id = engineer.id) ON company.id = employee.company_id WHERE employee.name = ? OR engineer.engineer_info = ? [...] ('SpongeBob', 'Senior Customer Engagement Engineer') Krusty Krab SpongeBob Krusty Krab Squidward
从上面可以观察到,直接加入到Engineer
目标,而不是使用with_polymorphic(Employee, [Engineer])
的“多态可选择”具有一个有用的特性,即使用内连接而不是左外连接,从 SQL 优化器的角度来看,这通常更具性能。
多态子类型的急切加载
在前一节中用Select.join()
方法演示的PropComparator.of_type()
也可以等效地应用于 relationship loader options,如selectinload()
和joinedload()
。
作为一个基本示例,如果我们希望加载Company
对象,并且使用with_polymorphic()
构造来对整个层次结构的Company.employees
的所有元素进行急切加载,我们可以编写如下代码:
>>> all_employees = with_polymorphic(Employee, "*") >>> stmt = select(Company).options(selectinload(Company.employees.of_type(all_employees))) >>> for company in session.scalars(stmt): ... print(f"company: {company.name}") ... print(f"employees: {company.employees}") SELECT company.id, company.name FROM company [...] () SELECT employee.company_id AS employee_company_id, employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, manager.id AS manager_id, manager.manager_name AS manager_manager_name, engineer.id AS engineer_id, engineer.engineer_info AS engineer_engineer_info FROM employee LEFT OUTER JOIN manager ON employee.id = manager.id LEFT OUTER JOIN engineer ON employee.id = engineer.id WHERE employee.company_id IN (?) [...] (1,) company: Krusty Krab employees: [Manager('Mr. Krabs'), Engineer('SpongeBob'), Engineer('Squidward')]
上述查询可以直接与前一节中将selectin_polymorphic()
应用于现有的急加载中的selectin_polymorphic()
版本进行比较。
另请参阅
将selectin_polymorphic()
应用于现有的急加载 - 演示了使用selectin_polymorphic()
相同等效的示例,而不是上面的例子。 ## 单一继承映射的 SELECT 语句
单一表继承设置
本节讨论单表继承,描述在单表继承中使用单个表表示层次结构中的多个类。
查看本节的 ORM 设置。
与联接继承映射相比,对于单一继承映射,构造 SELECT 语句往往更简单,因为对于全部单一继承层次结构,只有一个表。
无论继承层次结构是否全是单一继承或具有联接和单一继承的混合,单一继承的 SELECT 语句都通过添加额外的 WHERE 条件来区分针对基类和子类的查询。
例如,对于Employee
的单一继承示例映射的查询将使用简单的表 SELECT 加载Manager
、Engineer
和Employee
类型的对象:
>>> stmt = select(Employee).order_by(Employee.id) >>> for obj in session.scalars(stmt): ... print(f"{obj}") BEGIN (implicit) SELECT employee.id, employee.name, employee.type FROM employee ORDER BY employee.id [...] () Manager('Mr. Krabs') Engineer('SpongeBob') Engineer('Squidward')
当针对特定子类发出加载时,会向 SELECT 添加限制行的其他条件,例如下面对Engineer
实体执行的 SELECT:
>>> stmt = select(Engineer).order_by(Engineer.id) >>> objects = session.scalars(stmt).all() SELECT employee.id, employee.name, employee.type, employee.engineer_info FROM employee WHERE employee.type IN (?) ORDER BY employee.id [...] ('engineer',) >>> for obj in objects: ... print(f"{obj}") Engineer('SpongeBob') Engineer('Squidward')
优化单一继承的属性加载
单一继承映射关于如何选择子类上的属性的默认行为与联接继承的行为类似,即子类特定的属性仍然默认发出第二个 SELECT。在下面的示例中,加载一个Manager
类型的单个Employee
,但由于请求的类是Employee
,所以默认情况下不会出现Manager.manager_name
属性,并且当访问时会发出额外的 SELECT:
>>> mr_krabs = session.scalars(select(Employee).where(Employee.name == "Mr. Krabs")).one() BEGIN (implicit) SELECT employee.id, employee.name, employee.type FROM employee WHERE employee.name = ? [...] ('Mr. Krabs',) >>> mr_krabs.manager_name SELECT employee.manager_name AS employee_manager_name FROM employee WHERE employee.id = ? AND employee.type IN (?) [...] (1, 'manager') 'Eugene H. Krabs'
要更改此行为,对于单一继承以及联接继承加载中使用的额外属性的急加载,同样的一般概念也适用于单一继承,包括使用selectin_polymorphic()
选项以及with_polymorphic()
选项,后者简单地包含了额外的列,并且从 SQL 的角度来看,对于单一继承映射更有效:
>>> employees = with_polymorphic(Employee, "*") >>> stmt = select(employees).order_by(employees.id) >>> objects = session.scalars(stmt).all() BEGIN (implicit) SELECT employee.id, employee.name, employee.type, employee.manager_name, employee.engineer_info FROM employee ORDER BY employee.id [...] () >>> for obj in objects: ... print(f"{obj}") Manager('Mr. Krabs') Engineer('SpongeBob') Engineer('Squidward') >>> objects[0].manager_name 'Eugene H. Krabs'
由于加载单继承子类映射的开销通常很小,因此建议对于那些预计加载其特定子类属性是常见的子类,包括 Mapper.polymorphic_load
参数,并将其设置为 "inline"
。下面是一个示例,说明了包含此选项的 设置:
>>> class Base(DeclarativeBase): ... pass >>> class Employee(Base): ... __tablename__ = "employee" ... id: Mapped[int] = mapped_column(primary_key=True) ... name: Mapped[str] ... type: Mapped[str] ... ... def __repr__(self): ... return f"{self.__class__.__name__}({self.name!r})" ... ... __mapper_args__ = { ... "polymorphic_identity": "employee", ... "polymorphic_on": "type", ... } >>> class Manager(Employee): ... manager_name: Mapped[str] = mapped_column(nullable=True) ... __mapper_args__ = { ... "polymorphic_identity": "manager", ... "polymorphic_load": "inline", ... } >>> class Engineer(Employee): ... engineer_info: Mapped[str] = mapped_column(nullable=True) ... __mapper_args__ = { ... "polymorphic_identity": "engineer", ... "polymorphic_load": "inline", ... }
根据上述映射,Manager
和 Engineer
类将自动在针对 Employee
实体的 SELECT 语句中包含它们的列:
>>> print(select(Employee)) SELECT employee.id, employee.name, employee.type, employee.manager_name, employee.engineer_info FROM employee
继承加载 API
对象名称 | 描述 |
selectin_polymorphic(base_cls, classes) | 指示应对子类的所有属性进行急切加载。 |
with_polymorphic(base, classes[, selectable, flat, …]) | 生成一个 AliasedClass 构造,指定给定基类的后代映射器的列。 |
function sqlalchemy.orm.with_polymorphic(base: Type[_O] | Mapper[_O], classes: Literal['*'] | Iterable[Type[Any]], selectable: Literal[False, None] | FromClause = False, flat: bool = False, polymorphic_on: ColumnElement[Any] | None = None, aliased: bool = False, innerjoin: bool = False, adapt_on_names: bool = False, _use_mapper_path: bool = False) → AliasedClass[_O]
生成一个 AliasedClass
构造,指定给定基类的后代映射器的列。
使用此方法将确保每个后代映射器的表都包含在 FROM 子句中,并允许对这些表使用 filter() 条件。结果实例还将已加载这些列,因此不需要对这些列进行“后获取”。
另请参阅
使用 with_polymorphic() - 对 with_polymorphic()
的全面讨论。
参数:
base
– 要别名化的基类。classes
– 一个类或映射器,或类/映射器列表,它们都继承自基类。或者,它也可以是字符串'*'
,在这种情况下,所有下降映射的类都将添加到 FROM 子句中。aliased
– 当为 True 时,可选择的将被别名化。对于 JOIN,这意味着 JOIN 将从子查询中进行 SELECT,除非设置了with_polymorphic.flat
标志为 True,这对于简单的用例是推荐的。flat
– 布尔值,将传递给FromClause.alias()
调用,以便联接对象的别名别名联接内部的各个表,而不是创建子查询。这通常由所有现代数据库支持,关于右嵌套联接通常会产生更有效的查询。建议设置此标志,只要生成的 SQL 是功能性的。selectable
–
将用于替代生成的 FROM 子句的表或子查询。如果任何所需类使用具体表继承,则此参数是必需的,因为 SQLAlchemy 当前无法自动生成表之间的 UNION。如果使用,selectable
参数必须表示每个映射类映射的所有表和列的完整集。否则,未考虑的映射列将直接附加到 FROM 子句,这通常会导致不正确的结果。
当保持其默认值False
时,将为选择行使用分配给基本映射器的多态可选择对象。但是,也可以将其传递为None
,这将绕过配置的多态可选择对象,并代替构造给定目标类的临时可选择对象;对于联接表继承,这将是一个包含所有目标映射器及其子类的联接。polymorphic_on
– 用作给定可选择对象的“判别器”列。如果未提供,则将使用基类映射器的polymorphic_on
属性(如果有)。这对于默认没有多态加载行为的映射非常有用。innerjoin
– 如果为 True,则使用 INNER JOIN。只有在仅查询一个特定的子类型时才应指定此选项adapt_on_names
–
通过aliased.adapt_on_names
参数传递到别名对象。在给定可选择对象与现有映射的可选择对象没有直接关联的情况下,这可能会有所帮助。
自版本 1.4.33 起新增。
function sqlalchemy.orm.selectin_polymorphic(base_cls: _EntityType[Any], classes: Iterable[Type[Any]]) → _AbstractLoad
指示应针对特定子类的所有属性进行急加载。
这使用额外的 SELECT 与所有匹配的主键值进行 IN 比较,并且是与mapper.polymorphic_load
参数上的"selectin"
设置对应的每个查询的类似物。
自版本 1.2 起新增。
另请参阅
使用selectin_polymorphic()
从基类 vs. 特定子类进行 SELECT
对于联合继承层次结构中的类构建的 SELECT 语句将查询该类映射到的表,以及任何存在的超级表,使用 JOIN 将它们链接在一起。然后,该查询将返回请求类型的对象以及请求类型的任何子类型,使用每行中的鉴别器值来确定正确的类型。下面的查询是针对Employee
的Manager
子类建立的,然后返回的结果将仅包含Manager
类型的对象:
>>> from sqlalchemy import select >>> stmt = select(Manager).order_by(Manager.id) >>> managers = session.scalars(stmt).all() BEGIN (implicit) SELECT manager.id, employee.id AS id_1, employee.name, employee.type, employee.company_id, manager.manager_name FROM employee JOIN manager ON employee.id = manager.id ORDER BY manager.id [...] () >>> print(managers) [Manager('Mr. Krabs')]
当 SELECT 语句针对层次结构中的基类时,默认行为是仅包括该类的表在渲染的 SQL 中,并且不会使用 JOIN。与所有情况一样,鉴别器列用于区分不同的请求子类型,然后结果是返回任何可能的子类型的对象。返回的对象将具有与基本表对应的属性填充,而与子表对应的属性将以未加载状态开始,在访问时自动加载。子属性的加载可配置为以各种方式更加“急切”,这将在本节后面讨论。
下面的示例创建了针对Employee
超类的查询。这表示结果集中可能包含任何类型的对象,包括Manager
、Engineer
和Employee
:
>>> from sqlalchemy import select >>> stmt = select(Employee).order_by(Employee.id) >>> objects = session.scalars(stmt).all() BEGIN (implicit) SELECT employee.id, employee.name, employee.type, employee.company_id FROM employee ORDER BY employee.id [...] () >>> print(objects) [Manager('Mr. Krabs'), Engineer('SpongeBob'), Engineer('Squidward')]
上面,并未包括Manager
和Engineer
的附加表在 SELECT 中,这意味着返回的对象尚不包含来自这些表的数据,例如本示例中Manager
类的.manager_name
属性以及Engineer
类的.engineer_info
属性。这些属性起始处于过期状态,并且在首次访问时将自动填充自己,使用延迟加载:
>>> mr_krabs = objects[0] >>> print(mr_krabs.manager_name) SELECT manager.manager_name AS manager_manager_name FROM manager WHERE ? = manager.id [...] (1,) Eugene H. Krabs
如果已加载大量对象,则此惰性加载行为是不可取的,因为消费应用程序将需要访问特定于子类的属性,这将是一个 N 加一问题的示例,每行发出额外的 SQL。这些额外的 SQL 可能会影响性能,并且还可能与诸如使用 asyncio 等方法不兼容。此外,在我们对Employee
对象的查询中,由于查询仅针对基本表,因此我们无法以Manager
或Engineer
的术语添加涉及特定于子类的属性的 SQL 条件。接下来的两个部分详细介绍了两种以不同方式解决这两个问题的构造,selectin_polymorphic()
加载器选项和with_polymorphic()
实体构造。
SqlAlchemy 2.0 中文文档(十六)(3)https://developer.aliyun.com/article/1562944