SqlAlchemy 2.0 中文文档(十六)(2)

简介: SqlAlchemy 2.0 中文文档(十六)

SqlAlchemy 2.0 中文文档(十六)(1)https://developer.aliyun.com/article/1562941


使用 with_polymorphic() 过滤子类属性

with_polymorphic() 构造使包含的子类映射器上的属性可用,通过包含允许对子类的引用的命名空间。在前一节中创建的 employee_poly 构造包括名为 .Engineer.Manager 的属性,这些属性为 EngineerManager 提供了关于多态 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”时,查询也可以直接引用子类实体,其中它们隐式地表示多态查询中的连接表。在上面的例子中,我们可以自由地直接引用 ManagerEngineer 对默认的 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 加载ManagerEngineerEmployee类型的对象:

>>> 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",
...     }

根据上述映射,ManagerEngineer 类将自动在针对 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 将它们链接在一起。然后,该查询将返回请求类型的对象以及请求类型的任何子类型,使用每行中的鉴别器值来确定正确的类型。下面的查询是针对EmployeeManager子类建立的,然后返回的结果将仅包含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超类的查询。这表示结果集中可能包含任何类型的对象,包括ManagerEngineerEmployee

>>> 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')]

上面,并未包括ManagerEngineer的附加表在 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对象的查询中,由于查询仅针对基本表,因此我们无法以ManagerEngineer的术语添加涉及特定于子类的属性的 SQL 条件。接下来的两个部分详细介绍了两种以不同方式解决这两个问题的构造,selectin_polymorphic()加载器选项和with_polymorphic()实体构造。


SqlAlchemy 2.0 中文文档(十六)(3)https://developer.aliyun.com/article/1562944

相关文章
|
缓存 前端开发 API
API接口封装系列
API(Application Programming Interface)接口封装是将系统内部的功能封装成可复用的程序接口并向外部提供,以便其他系统调用和使用这些功能,通过这种方式实现系统之间的通信和协作。下面将介绍API接口封装的一些关键步骤和注意事项。
|
4月前
|
开发者 Docker 微服务
《深入探秘:从底层搭建Python微服务之FastAPI与Docker部署》
FastAPI是一款基于Python 3.6+的现代、高性能Web框架,结合Starlette和Pydantic优势,支持异步编程,性能媲美Go与Node.js。它内置输入验证、依赖注入功能,自动生成交互式API文档,大幅提升开发效率与代码质量。Docker容器技术通过封装应用及其依赖,实现“一次构建,到处运行”,解决环境差异问题,提供轻量级、高效的部署方案。两者结合助力快速搭建稳定、高效的Python微服务架构,满足高并发与弹性伸缩需求,推动现代化应用开发。
171 9
《深入探秘:从底层搭建Python微服务之FastAPI与Docker部署》
|
2月前
|
人工智能 Java API
后端开发必看:零代码实现存量服务改造成MCP服务
本文介绍如何通过 **Nacos** 和 **Higress** 实现存量 Spring Boot 服务的零代码改造,使其支持 MCP 协议,供 AI Agent 调用。全程无需修改业务代码,仅通过配置完成服务注册、协议转换与工具映射,显著降低改造成本,提升服务的可集成性与智能化能力。
476 0
|
6月前
|
人工智能 安全 API
0 代码为你的 Typecho 博客接入阿里云百炼(可接入 DeepSeek-R1 满血版!)
随着科技企业LLM发展成熟,AIHelper插件让Typecho博客轻松拥有AI助手。通过集成阿里云百炼API,支持DeepSeek-R1、Qwen等模型,帮助读者快速查找内容、总结文章。本文详细介绍了从导出文章、配置阿里云百炼、创建AI应用到安装配置插件的全过程,确保安全高效地为博客添加智能交互功能。相比官方方案,AIHelper提供更安全的访问限制和低代码部署方式,无需编写代码即可实现智能化管理。
0 代码为你的 Typecho 博客接入阿里云百炼(可接入 DeepSeek-R1 满血版!)
|
7月前
|
人工智能 算法 搜索推荐
单纯接入第三方模型就无需算法备案了么?
随着人工智能的发展,企业接入第三方模型提升业务能力的现象日益普遍,但算法备案问题引发诸多讨论。根据相关法规,无论使用自研或第三方模型,只要涉及向中国境内公众提供算法推荐服务,企业均需履行备案义务。这不仅因为服务性质未变,风险依然存在,也符合监管要求。备案内容涵盖模型基本信息、算法优化目标等,且需动态管理。未备案可能面临法律和运营风险。建议企业提前规划、合规管理和积极沟通,确保合法合规运营。
2024年 | 7月云大使推广奖励规则
①【近期云大使规则升级】提升首购后订单返利比例、新增沉睡用户返利 、增加企业用户加入云大使、增加返利订单类目、优化推广奖励限制。②推荐企业认证新用户首购最高奖励45%。
|
Rust 安全 C++
游戏引擎的未来:是Rust成为新王,还是C++仍占鳌头?
【8月更文挑战第31天】随着游戏行业的快速发展,对高性能、安全且易维护的游戏引擎需求日益增长。虽然C++长期占据主导地位,但Rust语言凭借其内存安全和高性能的特点,逐渐成为游戏引擎开发的新选择。Rust通过所有权机制和强大的类型系统,在保证内存安全的同时实现了与C++相当的性能,有助于提前发现潜在错误。尽管Rust在生态系统成熟度和学习曲线上仍面临挑战,其在游戏引擎领域的潜力正逐渐被认可。随着Rust社区的发展和工具链的完善,Rust有望成为游戏引擎开发的重要选项。
518 0
|
JSON API 数据安全/隐私保护
如何使用Fastapi上传文件?先从请求体数据讲起
如何使用Fastapi上传文件?先从请求体数据讲起
512 2
|
前端开发
前端Vue2获取上传文件的MD5
前端Vue2获取上传文件的MD5
|
JSON 前端开发 JavaScript
将 JavaScript 对象或值转换为 JSON 字符串:JSON.stringify()
将 JavaScript 对象或值转换为 JSON 字符串:JSON.stringify()
390 3