映射器可以针对任意关系单元(调用 可选择的 )除了普通的表格。例如, join()
函数创建一个由多个表组成的可选单元,并使用自己的复合主键完成,该主键可以与 Table
::
from sqlalchemy import Table, Column, Integer, \
String, MetaData, join, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import column_property
metadata = MetaData()
# define two Table objects
user_table = Table('user', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
)
address_table = Table('address', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('user.id')),
Column('email_address', String)
)
# define a join between them. This
# takes place across the user.id and address.user_id
# columns.
user_address_join = join(user_table, address_table)
Base = declarative_base()
# map to it
class AddressUser(Base):
__table__ = user_address_join
id = column_property(user_table.c.id, address_table.c.user_id)
address_id = address_table.c.id
在上面的示例中,join表示 user
以及 address
表。这个 user.id
和 address.user_id
列与外键相等,因此在映射中它们被定义为一个属性, AddressUser.id
使用 column_property()
指示专用列映射。根据配置的这一部分,映射将从 user.id
进入 address.user_id
发生刷新时的列。
另外, address.id
列显式映射到名为 address_id
. 这是为了 消除歧义 的映射 address.id
来自相同名称的列 AddressUser.id
属性,此处已分配用于引用 user
表与 address.user_id
外键。
上述映射的自然主键是 (user.id, address.id)
,因为这些是 user
和 address
表格合并在一起。的标识 AddressUser
对象将以这两个值表示,并由 AddressUser
对象AS (AddressUser.id, AddressUser.address_id)
.
类似于针对连接的映射,普通 select()
对象也可以与映射器一起使用。下面的示例片段说明如何映射一个名为 Customer
到A select()
其中包括到子查询的联接:
from sqlalchemy import select, func
subq = select([
func.count(orders.c.id).label('order_count'),
func.max(orders.c.price).label('highest_order'),
orders.c.customer_id
]).group_by(orders.c.customer_id).alias()
customer_select = select([customers, subq]).\
select_from(
join(customers, subq,
customers.c.id == subq.c.customer_id)
).alias()
class Customer(Base):
__table__ = customer_select
上面的整行由 customer_select
将是所有列的 customers
表,除了 subq
子查询,即 order_count
, highest_order
和 customer_id
. 映射 Customer
然后创建一个包含这些属性的类。
当ORM保持新的 Customer
,只有 customers
表将实际接收一个插入。这是因为 orders
映射中不表示表;ORM将只向其映射了主键的表中发出一个插入。
在现代的SQLAlchemy中,一个特定的类只被一个所谓的 初级的 一次映射。这个映射器涉及三个主要功能领域:查询、持久性和映射类的插入。主映射器的基本原理与以下事实有关: mapper()
修改类本身,不仅将其持久化到特定的 Table
,而且 instrumenting 类上的属性,这些属性是根据表元数据专门构造的。不可能有多个映射器以相同的度量与类关联,因为实际上只有一个映射器可以对类进行检测。
然而,有一类映射器称为 非初级 允许附加映射器与类关联,但使用范围有限的映射器。此范围通常适用于能够从备用表或可选单元加载行,但仍然生成使用主映射最终持久化的类。非主映射器是根据已经用主映射器映射的类使用经典的映射样式创建的,它涉及使用 non_primary
标志。
非主映射器在现代SQLAlchemy中的使用非常有限,因为现在可以使用 Query
直接对象。
对于非主映射器,实际上只有一个用例,即我们希望构建一个 relationship()
对于这样一个映射器,这在我们的关系正试图使用多个表和/或表之间的联接将两个类连接在一起的罕见和高级情况下非常有用。此模式的一个示例位于 relationship_non_primary_mapper .
就一个类的用例而言,它实际上可以在不同的场景下完全持久化到不同的表中,非常早的SQLAlchemy版本提供了一个从Hibernate改编的特性,称为“实体名”特性。然而,一旦映射的类本身成为SQL表达式构造的源,这种用例在sqlAlchemy中就变得不可行;也就是说,类的属性本身直接链接到映射的表列。该特性被删除,并替换为一种简单的面向方法的方法来完成这项任务,而不需要使用任何含糊不清的工具——创建新的子类,每个子类都单独映射。此模式现在可作为方法在 Entity Name .