Release: 1.4.25 | Release Date: September 22, 2021

SQLAlchemy 1.4 Documentation

正在加载继承层次结构

当使用“joined”、“single”或“concrete”表继承样式在继承层次结构中映射类时,如中所述 映射类继承层次结构 通常的行为是,对特定基类的查询也将生成与子类相对应的对象。当单个查询能够返回每个结果行具有不同类或子类的结果时,我们使用术语“多态加载”。

在多态加载领域,特别是联合表继承和单表继承,还有一个额外的问题,子类属性需要预先查询,然后再加载。当预先查询某个特定子类的属性时,我们可以在查询中使用它作为要过滤的对象,当我们取回对象时,它也将被加载。如果它不是预先查询的,那么当我们第一次需要访问它时,它会在稍后加载。此行为的基本控制是使用 with_polymorphic() 函数,以及两个变量,映射器配置 mapper.with_polymorphicmapper.polymorphic_load 选项,以及 Query 水平 Query.with_polymorphic() 方法。“with_多态”系列每个都提供了一种方法,用于指定在查询中应包括特定基类的哪些特定子类,这意味着选择中可以使用哪些列和表。

与多态性一起使用

对于以下部分,假设 Employee / Engineer / Manager 示例介绍于 映射类继承层次结构 .

通常,当 Query 指定继承层次结构的基类,仅查询该基类的本地列::

session.query(Employee).all()

上面,对于单表继承和联接表继承,只有本地列 Employee 将出现在选择中。我们可以取回 EngineerManager 但是,在我们第一次访问它们之前,它们不会加载其他属性,此时将发出一个延迟加载。

同样,如果我们想引用映射到 EngineerManager 在我们的质询中 Employee ,这些列在单表继承或联接表继承情况下都不直接可用,因为 Employee 实体不引用这些列(请注意,对于单表继承,如果使用声明性的,这是很常见的,但对于经典映射则不常见)。

为了解决这两个问题, with_polymorphic() 函数提供一个特殊的 AliasedClass 它表示跨子类的一系列列。此对象可用于 Query 像其他别名一样。查询时,它表示给定类中存在的所有列:

from sqlalchemy.orm import with_polymorphic

eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])

query = session.query(eng_plus_manager)

如果上面的映射使用联接表继承,上面的select语句将是:

query.all()
SELECT employee.id AS employee_id, engineer.id AS engineer_id, manager.id AS manager_id, employee.name AS employee_name, employee.type AS employee_type, engineer.engineer_info AS engineer_engineer_info, manager.manager_data AS manager_manager_data FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id LEFT OUTER JOIN manager ON employee.id = manager.id []

在上面的位置,包括“工程师”和“经理”的附加表/列。在单表继承的情况下也会发生类似的行为。

with_polymorphic() 接受单个类或映射器、类/映射器列表或字符串 '*' 要指示所有子类:

# include columns for Engineer
entity = with_polymorphic(Employee, Engineer)

# include columns for Engineer, Manager
entity = with_polymorphic(Employee, [Engineer, Manager])

# include columns for all mapped subclasses
entity = with_polymorphic(Employee, '*')

小技巧

值得注意的是, with_polymorphic() 仅影响 读取的行中包含的列 ,而不是 返回的对象类型 。打电话给 with_polymorphic(Employee, [Manager]) 将引用包含所有类型的 Employee 对象,不仅包括 Manager 对象,但也 Engineer 对象,因为这些对象是 Employee ,以及 Employee 实例(如果数据库中存在这些实例)。使用的效果 with_polymorphic(Employee, [Manager]) 仅提供特定于以下内容的附加列的行为 Manager 将被急切地加载到结果行中,如下所述 引用特定的子类属性 也可在SELECT语句的WHERE子句中使用。

将混叠与多态性一起使用

这个 with_polymorphic() 函数还提供多态选择本身的“混叠”,也就是说,两个不同的 with_polymorphic() 引用同一类层次结构的实体可以一起使用。可以使用 with_polymorphic.aliased 旗子。对于跨多个表的多态可选项,默认行为是将可选项包装到子查询中。下面我们将发出一个查询,该查询将选择“employee or manager”与“employee or engineer”对同名员工:

engineer_employee = with_polymorphic(
    Employee, [Engineer], aliased=True)
manager_employee = with_polymorphic(
    Employee, [Manager], aliased=True)

q = s.query(engineer_employee, manager_employee).\
    join(
        manager_employee,
        and_(
            engineer_employee.id > manager_employee.id,
            engineer_employee.name == manager_employee.name
        )
)
q.all()
SELECT anon_1.employee_id AS anon_1_employee_id, anon_1.employee_name AS anon_1_employee_name, anon_1.employee_type AS anon_1_employee_type, anon_1.engineer_id AS anon_1_engineer_id, anon_1.engineer_engineer_name AS anon_1_engineer_engineer_name, anon_2.employee_id AS anon_2_employee_id, anon_2.employee_name AS anon_2_employee_name, anon_2.employee_type AS anon_2_employee_type, anon_2.manager_id AS anon_2_manager_id, anon_2.manager_manager_name AS anon_2_manager_manager_name FROM ( SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, engineer.id AS engineer_id, engineer.engineer_name AS engineer_engineer_name FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id ) AS anon_1 JOIN ( SELECT 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 FROM employee LEFT OUTER JOIN manager ON employee.id = manager.id ) AS anon_2 ON anon_1.employee_id > anon_2.employee_id AND anon_1.employee_name = anon_2.employee_name

上面的子查询的创建非常冗长。虽然它创建了两个不同查询的最佳封装,但可能效率低下。 with_polymorphic() 包括一个额外的标志来帮助处理这种情况, with_polymorphic.flat 它将把子查询/联接组合“展平”为直接联接,而对单个表应用别名。设置 with_polymorphic.flat 暗示 with_polymorphic.aliased ,因此只需要一个标志:

engineer_employee = with_polymorphic(
    Employee, [Engineer], flat=True)
manager_employee = with_polymorphic(
    Employee, [Manager], flat=True)

q = s.query(engineer_employee, manager_employee).\
    join(
        manager_employee,
        and_(
            engineer_employee.id > manager_employee.id,
            engineer_employee.name == manager_employee.name
        )
)
q.all()
SELECT employee_1.id AS employee_1_id, employee_1.name AS employee_1_name, employee_1.type AS employee_1_type, engineer_1.id AS engineer_1_id, engineer_1.engineer_name AS engineer_1_engineer_name, employee_2.id AS employee_2_id, employee_2.name AS employee_2_name, employee_2.type AS employee_2_type, manager_1.id AS manager_1_id, manager_1.manager_name AS manager_1_manager_name FROM employee AS employee_1 LEFT OUTER JOIN engineer AS engineer_1 ON employee_1.id = engineer_1.id JOIN ( employee AS employee_2 LEFT OUTER JOIN manager AS manager_1 ON employee_2.id = manager_1.id ) ON employee_1.id > employee_2.id AND employee_1.name = employee_2.name

使用时,请注意上述内容 with_polymorphic.flat ,当与联接表继承结合使用时,通常情况下,我们在语句中得到一个正确的嵌套联接。一些较旧的数据库,特别是较旧版本的sqlite,可能会遇到这种语法问题,尽管现在几乎所有现代数据库版本都支持这种语法。

注解

这个 with_polymorphic.flat 标志仅适用于 with_polymorphic 具有 联接表继承with_polymorphic.selectable 论证是 not 使用。

引用特定的子类属性

返回的实体 with_polymorphic() 是一个 AliasedClass 对象,可以在 Query 和其他别名一样,包括 Employee 班级。在前面的示例中, eng_plus_manager 成为我们用来引用上面的三向外部联接的实体。它还包括类列表中命名的每个类的名称空间,以便也可以调用这些子类的特定属性。下面的示例说明调用特定于 Engineer 以及 Manager 依据 eng_plus_manager ::

eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])
query = session.query(eng_plus_manager).filter(
                or_(
                    eng_plus_manager.Engineer.engineer_info=='x',
                    eng_plus_manager.Manager.manager_data=='y'
                )
            )

如上所述的查询将生成如下所示的SQL:

query.all()
SELECT employee.id AS employee_id, engineer.id AS engineer_id, manager.id AS manager_id, employee.name AS employee_name, employee.type AS employee_type, engineer.engineer_info AS engineer_engineer_info, manager.manager_data AS manager_manager_data FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id LEFT OUTER JOIN manager ON employee.id = manager.id WHERE engineer.engineer_info=? OR manager.manager_data=? ['x', 'y']

在映射器配置时使用多态性设置

这个 with_polymorphic() 函数的作用是允许从子类表中“急”加载属性,以及在查询时引用子类表中的属性。从历史上看,柱的“急加载”是方程式中更重要的部分。因此,正如对关系的渴望加载可以被指定为配置选项一样, mapper.with_polymorphic 默认情况下,配置参数允许实体使用多态加载。我们可以将参数添加到 Employee 首次引入映射于 联接表继承 ::

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    type = Column(String(50))

    __mapper_args__ = {
        'polymorphic_identity':'employee',
        'polymorphic_on':type,
        'with_polymorphic': '*'
    }

上面是一个常见的设置 mapper.with_polymorphic ,表示要加载所有子类列的星号。在联接表继承的情况下,应谨慎使用此选项,因为它意味着映射将始终向多个表发出一系列(通常是大的)左外部联接,从SQL的角度来看,这是不高效的。对于单表继承,指定星号通常是一个好主意,因为加载仍然只针对一个表,但是会阻止子类映射列的额外延迟加载。

使用 with_polymorphic()Query.with_polymorphic() 将覆盖映射器级别 mapper.with_polymorphic 设置。

这个 mapper.with_polymorphic 选项还接受类列表,就像 with_polymorphic() 在类的子集中以多态方式加载。但是,在使用声明性的时候,不能直接向这个列表提供类,因为我们要添加的子类还不可用。相反,我们可以在每个子类上指定,默认情况下,它们应该单独参与多态加载,使用 mapper.polymorphic_load 参数::

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    engineer_info = Column(String(50))
    __mapper_args__ = {
        'polymorphic_identity':'engineer',
        'polymorphic_load': 'inline'
    }

class Manager(Employee):
    __tablename__ = 'manager'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    manager_data = Column(String(50))
    __mapper_args__ = {
        'polymorphic_identity':'manager',
        'polymorphic_load': 'inline'
    }

设置 mapper.polymorphic_load 值的参数 "inline" 意味着 EngineerManager 上面的类是基础的“多态负载”的一部分 Employee 默认情况下,就像它们被附加到 mapper.with_polymorphic 课程列表。

对查询使用多态性设置

这个 with_polymorphic() 从查询级别方法演变而来的函数 Query.with_polymorphic() . 此方法的目的与 with_polymorphic() ,但它的使用模式没有那么灵活,因为它只适用于 Query . 然后,它对该实体的所有出现都生效,这样就可以直接引用该实体(及其子类),而不是使用别名对象。对于简单的情况,可以认为更简洁:

session.query(Employee).\
    with_polymorphic([Engineer, Manager]).\
    filter(
        or_(
            Engineer.engineer_info=='w',
            Manager.manager_data=='q'
        )
    )

这个 Query.with_polymorphic() 方法的工作比 with_polymorphic() 函数,因为它需要正确地转换 EngineerManager 适当,但不干扰其他实体。如果缺少灵活性,请切换到使用 with_polymorphic() .

多态性选择素加载

替代使用 with_polymorphic() 在继承映射上“急切地”加载附加子类的函数家族,主要是在使用联合表继承时,将使用多态的“selectin”加载。这是一个紧急加载功能,其工作原理与 加载时选择 关系加载的功能。对于我们的示例映射,我们可以指示 Employee 通过使用 selectin_polymorphic() 加载器选项:

from sqlalchemy.orm import selectin_polymorphic

query = session.query(Employee).options(
    selectin_polymorphic(Employee, [Manager, Engineer])
)

当运行上述查询时,将发出两条附加的select语句:

query.all() SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type FROM employee () SELECT engineer.id AS engineer_id, employee.id AS employee_id, employee.type AS employee_type, engineer.engineer_name AS engineer_engineer_name FROM employee JOIN engineer ON employee.id = engineer.id WHERE employee.id IN (?, ?) ORDER BY employee.id (1, 2) SELECT manager.id AS manager_id, employee.id AS employee_id, employee.type AS employee_type, manager.manager_name AS manager_manager_name FROM employee JOIN manager ON employee.id = manager.id WHERE employee.id IN (?) ORDER BY employee.id (3,)

我们也可以通过指定 mapper.polymorphic_load 参数,使用值 "selectin" 根据子类:

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    type = Column(String(50))

    __mapper_args__ = {
        'polymorphic_identity': 'employee',
        'polymorphic_on': type
    }

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    engineer_name = Column(String(30))

    __mapper_args__ = {
        'polymorphic_load': 'selectin',
        'polymorphic_identity': 'engineer',
    }

class Manager(Employee):
    __tablename__ = 'manager'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    manager_name = Column(String(30))

    __mapper_args__ = {
        'polymorphic_load': 'selectin',
        'polymorphic_identity': 'manager',
    }

与使用时不同 with_polymorphic() ,当使用 selectin_polymorphic() 装载方式,我们有 not 有能力参考 EngineerManager 主查询中的实体作为筛选、排序依据或其他条件,因为这些实体在用于定位结果的初始查询中不存在。但是,我们可以应用应用于 EngineerManager ,在发出次选择时生效。下面我们假设 Manager 有额外的关系 Manager.paperwork ,我们也很乐意装载。我们可以使用任何类型的预加载,例如通过 joinedload() 功能:

from sqlalchemy.orm import joinedload
from sqlalchemy.orm import selectin_polymorphic

query = session.query(Employee).options(
    selectin_polymorphic(Employee, [Manager, Engineer]),
    joinedload(Manager.paperwork)
)

使用上面的查询,我们得到三个发出的select语句,但是其中一个针对 Manager 将:

SELECT
    manager.id AS manager_id,
    employee.id AS employee_id,
    employee.type AS employee_type,
    manager.manager_name AS manager_manager_name,
    paperwork_1.id AS paperwork_1_id,
    paperwork_1.manager_id AS paperwork_1_manager_id,
    paperwork_1.data AS paperwork_1_data
FROM employee JOIN manager ON employee.id = manager.id
LEFT OUTER JOIN paperwork AS paperwork_1
ON manager.id = paperwork_1.manager_id
WHERE employee.id IN (?) ORDER BY employee.id
(3,)

注意,selectin多态加载与selectin关系加载有类似的注意事项;对于使用复合主键的实体,使用中的数据库必须支持tuples with“in”,目前已知该tuples可用于mysql和postgresql。

1.2 新版功能.

警告

选择素多态性加载特征应被视为 实验的 在1.2系列的早期版本中。

选择素与多态性结合

注解

自1.2.0b3起工作

经过仔细规划,selectin加载可以应用于自身使用“with_多态性”的层次结构。一个特殊的用例是使用selectin加载来加载一个连接的继承子表,然后使用“with_多态性”来引用更多的子类,这些子类可以是连接的或单表继承。如果我们添加了一个类 VicePresident 延伸的 Manager 使用单表继承,我们可以确保 Manager 同时满载 VicePresident 同时的子类型:

# use "Employee" example from the enclosing section

class Manager(Employee):
    __tablename__ = 'manager'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    manager_name = Column(String(30))

    __mapper_args__ = {
        'polymorphic_load': 'selectin',
        'polymorphic_identity': 'manager',
    }

class VicePresident(Manager):
    vp_info = Column(String(30))

    __mapper_args__ = {
        "polymorphic_load": "inline",
        "polymorphic_identity": "vp"
    }

以上,我们添加了 vp_info 列到 manager 表,本地 VicePresident 子类。这个子类与多态性身份有关。 "vp" 它指的是具有此数据的行。通过将加载样式设置为“inline”,这意味着 Manager 对象还将确保 vp_info 在同一个select语句中查询列。对…的质疑 Employee 遇到一个 Manager 行将发出类似于以下内容的内容:

SELECT employee.id AS employee_id, employee.name AS employee_name,
       employee.type AS employee_type
FROM employee
)

SELECT manager.id AS manager_id, employee.id AS employee_id,
       employee.type AS employee_type,
       manager.manager_name AS manager_manager_name,
       manager.vp_info AS manager_vp_info
FROM employee JOIN manager ON employee.id = manager.id
WHERE employee.id IN (?) ORDER BY employee.id
(1,)

结合“selectin”多态加载和查询时间 with_polymorphic() 也可以使用(尽管这是非常外层空间的东西!);假设上述映射没有 polymorphic_load 设置,我们可以得到如下相同的结果:

from sqlalchemy.orm import with_polymorphic, selectin_polymorphic

manager_poly = with_polymorphic(Manager, [VicePresident])

s.query(Employee).options(
    selectin_polymorphic(Employee, [manager_poly])).all()

在关系中引用特定的子类型

对应于 relationship() 用于查询以引用两个映射之间的链接。常用的用法是指 relationship() 在里面 Query.join() 以及加载程序选项,如 joinedload() . 使用时 relationship() 如果目标类是继承层次结构,则API允许联接、预加载或其他链接以特定的子类、别名或 with_polymorphic() 该类层次结构的别名,而不是 relationship() .

这个 of_type() 方法允许沿着 relationship() 将条件缩小到特定派生别名或子类时的路径。假设 employees 表表示与 Company 对象。我们将添加一个 company_id 列到 employees 桌子和新桌子 companies

class Company(Base):
    __tablename__ = 'company'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    employees = relationship("Employee",
                    backref='company')

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer, primary_key=True)
    type = Column(String(20))
    company_id = Column(Integer, ForeignKey('company.id'))
    __mapper_args__ = {
        'polymorphic_on':type,
        'polymorphic_identity':'employee',
    }

class Engineer(Employee):
    __tablename__ = 'engineer'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    engineer_info = Column(String(50))
    __mapper_args__ = {'polymorphic_identity':'engineer'}

class Manager(Employee):
    __tablename__ = 'manager'
    id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
    manager_data = Column(String(50))
    __mapper_args__ = {'polymorphic_identity':'manager'}

从查询时 CompanyEmployee 关系 Query.join() 方法和运算符 PropComparator.any()PropComparator.has() 将从创建联接 companyemployee ,不包括 engineermanager 在混合中。如果我们希望有一个特别反对 Engineer 类,我们可以告诉这些方法使用 PropComparator.of_type() 操作员:

session.query(Company).\
    join(Company.employees.of_type(Engineer)).\
    filter(Engineer.engineer_info=='someinfo')

同样,从 Company 到包含两个元素的多态实体 EngineerManager 柱::

manager_and_engineer = with_polymorphic(
                            Employee, [Manager, Engineer])

session.query(Company).\
    join(Company.employees.of_type(manager_and_engineer)).\
    filter(
        or_(
            manager_and_engineer.Engineer.engineer_info == 'someinfo',
            manager_and_engineer.Manager.manager_data == 'somedata'
        )
    )

这个 PropComparator.any()PropComparator.has() 操作员也可以与 of_type() 例如,当嵌入的条件是子类时:

session.query(Company).\
        filter(
            Company.employees.of_type(Engineer).
                any(Engineer.engineer_info=='someinfo')
            ).all()

特异性或多态性亚型的热切加载

这个 joinedload()subqueryload()contains_eager() 和其他热切装载机选项支持使用 of_type() . 下面,我们载入 Company 行,同时加载相关的 Engineer 对象,查询 employeeengineer 同时表格:

session.query(Company).\
    options(
        subqueryload(Company.employees.of_type(Engineer)).
        subqueryload(Engineer.machines)
        )
    )

情况也是如此 Query.join()PropComparator.of_type() 可用于将预加载和 with_polymorphic() ,以便可以加载所有引用子类型的所有子属性::

manager_and_engineer = with_polymorphic(
                            Employee, [Manager, Engineer],
                            flat=True)

session.query(Company).\
    options(
        joinedload(
            Company.employees.of_type(manager_and_engineer)
        )
    )

注解

使用时 with_polymorphic()joinedload() , the with_polymorphic() 对象必须与“别名”对象相对,该对象是 Alias ,以便对多态可选对象进行别名处理(否则将引发信息性错误消息)。

典型的方法是包括 with_polymorphic.aliasedflat 标志,它将自动应用此别名。但是,如果 with_polymorphic.selectable 参数正用于传递已经是 Alias 对象,则此标志应 not 被设定。“flat”选项意味着“aliased”选项,它是针对产生较少子查询的联接对象的别名的另一种形式。

一次 PropComparator.of_type() 是渴望加载的目标,这是我们将用于后续链接的实体,而不是原始类或派生类。如果我们想进一步将一个集合加载到 Engineer 类,我们从 with_polymorphic() 对象:

session.query(Company).\
    options(
        joinedload(Company.employees.of_type(manager_and_engineer)).\
        subqueryload(manager_and_engineer.Engineer.computers)
        )
    )

正在加载具有联接表继承的对象

当使用联接表继承时,如果我们查询表示两个表(如 Engineer 继承部分的示例中,发出的SQL是一个联接::

session.query(Engineer).all()

上面的查询将发出类似SQL的信息:

SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, engineer.name AS engineer_name FROM employee JOIN engineer ON employee.id = engineer.id

然后我们会收集 Engineer 对象返回,其中将包含来自 employeeengineer 加载。

但是,当发出 Query 对于基类,行为仅从基表加载::

session.query(Employee).all()

在上面,默认行为将是仅从 employee 表而不是任何“子”表 (engineermanager ,在前面的示例中):

SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type FROM employee []

在收集 Employee 对象已从查询中返回,因为属性是从这些查询中请求的 Employee 对象,在 engineermanager 子表,如果尚未加载数据,则为该相关行中的列发出第二次加载。因此,在访问对象之后,您将看到沿着以下行发布的更多SQL:

SELECT manager.id AS manager_id, manager.manager_data AS manager_manager_data FROM manager WHERE ? = manager.id [5] SELECT engineer.id AS engineer_id, engineer.engineer_info AS engineer_engineer_info FROM engineer WHERE ? = engineer.id [2]

这个 with_polymorphic() 函数和相关的配置选项允许我们发出一个预先连接,它将根据 employeeengineermanager ,非常类似于joined-eager-loading为关系工作,消除了每个实体加载一秒钟的必要性:

from sqlalchemy.orm import with_polymorphic

eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])

query = session.query(eng_plus_manager)

上面生成的查询将 employee 两人的桌子 engineermanager 如下表格:

query.all()
SELECT employee.id AS employee_id, engineer.id AS engineer_id, manager.id AS manager_id, employee.name AS employee_name, employee.type AS employee_type, engineer.engineer_info AS engineer_engineer_info, manager.manager_data AS manager_manager_data FROM employee LEFT OUTER JOIN engineer ON employee.id = engineer.id LEFT OUTER JOIN manager ON employee.id = manager.id []

断面 与多态性一起使用 讨论 with_polymorphic() 函数及其构型变体。

加载具有单表继承的对象

在现代的声明式中,单继承映射产生 Column 对象只映射到一个子类,而不从超类中可用,即使它们存在于同一个表中。在我们的示例中, 单表继承 , the Manager 例如,映射具有 Column 明确规定::

class Manager(Employee):
    manager_data = Column(String(50))

    __mapper_args__ = {
        'polymorphic_identity':'manager'
    }

上面没有 Employee.manager_data 属性,即使 employee 表有 manager_data 列。对…的质疑 Manager 将在查询中包含此列,以及只将行限制为的In子句 Manager 物体:

session.query(Manager).all()
SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, employee.manager_data AS employee_manager_data FROM employee WHERE employee.type IN (?) ('manager',)

但是,以与联接表继承类似的方式,查询 Employee 将只查询映射到的列 Employee

session.query(Employee).all()
SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type FROM employee

如果我们得到一个 Manager 根据我们的结果,访问附加的列只映射到 Manager 以类似于联接继承的方式为这些列发出延迟加载:

SELECT employee.manager_data AS employee_manager_data
FROM employee
WHERE employee.id = ? AND employee.type IN (?)

这个 with_polymorphic() 在单继承的情况下,函数的作用类似于联合继承;它既允许预先加载子类属性,也允许在查询中指定子类,而不需要使用外部联接的开销:

employee_poly = with_polymorphic(Employee, '*')

q = session.query(employee_poly).filter(
    or_(
        employee_poly.name == 'a',
        employee_poly.Manager.manager_data == 'b'
    )
)

上面,我们的查询仍然针对单个表,但是我们可以引用 ManagerEngineer 使用“多态”名称空间。因为我们指定了 "*" 对于实体,两者都是 EngineerManager 将立即加载。发出的SQL将是:

q.all()
SELECT employee.id AS employee_id, employee.name AS employee_name, employee.type AS employee_type, employee.manager_data AS employee_manager_data, employee.engineer_info AS employee_engineer_info FROM employee WHERE employee.name = :name_1 OR employee.manager_data = :manager_data_1

继承加载API

Object Name Description

selectin_polymorphic(base_cls, classes)

指示应为特定于子类的所有属性执行一个紧急加载。

with_polymorphic(base, classes[, selectable, flat, ...])

产生一个 AliasedClass 为给定基的后代映射器指定列的构造。

function sqlalchemy.orm.with_polymorphic(base, classes, selectable=False, flat=False, polymorphic_on=None, aliased=False, innerjoin=False, _use_mapper_path=False, _existing_alias=None)

产生一个 AliasedClass 为给定基的后代映射器指定列的构造。

使用此方法将确保每个子代映射器的表都包含在FROM子句中,并允许对这些表使用filter()条件。结果实例还将加载这些列,这样就不需要对这些列进行“后提取”。

参数
  • base -- 要别名的基类。

  • classes -- 从基类继承的单个类或映射器或类/映射器列表。或者,它也可以是字符串 '*' 在这种情况下,所有降序映射类都将添加到FROM子句中。

  • aliased -- 如果为True,则可选择项将具有别名。对于联接,这意味着将从子查询内部选择联接,除非 with_polymorphic.flat flag设置为True,对于更简单的用例,建议这样做。

  • flat -- 布尔值,将传递给 FromClause.alias() 调用以便 Join 对象将对联接内的各个表进行别名,而不是创建子查询。对于右嵌套联接,这通常由所有现代数据库支持,并且通常生成更高效的查询。只要生成的SQL正常工作,就建议设置此标志。

  • selectable -- 一种表或子查询,它将用来代替生成自子句。如果任何所需类使用具体的表继承,则需要此参数,因为SQLAlchemy当前无法在表之间自动生成联合。如果使用,则 selectable 参数必须表示由每个映射类映射的完整表和列集。否则,未计数的映射列将导致其表直接附加到FROM子句,这通常会导致错误的结果。

  • polymorphic_on -- 要用作给定可选项的“鉴别器”列的列。如果没有给出,将使用基类映射器的多态性属性(如果有的话)。这对于默认情况下没有多态加载行为的映射很有用。

  • innerjoin -- 如果为true,则将使用内部联接。只有在仅查询一个特定子类型时才应指定此项

function sqlalchemy.orm.selectin_polymorphic(base_cls, classes)

指示应为特定于子类的所有属性执行一个紧急加载。

这将对所有匹配的主键值使用一个带有in的附加select,并且每个查询类似于 "selectin" 设置在 mapper.polymorphic_load 参数。

1.2 新版功能.

Previous: 关系加载技术 Next: 构造函数和对象初始化