SQLAlchemy 2.0 文档
使用声明式配置映射器¶
映射类基本组件 部分讨论了 Mapper
构造的一般配置元素,该构造定义了特定的用户定义类如何映射到数据库表或其他 SQL 构造。以下部分详细描述了声明式系统如何构建 Mapper
。
使用声明式定义映射属性¶
使用声明式配置表 中给出的示例说明了针对绑定到表的列的映射,使用了 mapped_column()
构造。除了绑定到表的列之外,还有几种其他类型的 ORM 映射构造可以配置,最常见的是 relationship()
构造。其他类型的属性包括使用 column_property()
构造定义的 SQL 表达式,以及使用 composite()
构造的多列映射。
虽然 命令式映射 使用 properties 字典来建立所有映射的类属性,但在声明式映射中,这些属性都在类定义中内联指定,在声明式表映射的情况下,这些属性与将用于生成 Table
对象的 Column
对象内联。
使用 User
和 Address
的示例映射,我们可以说明一个声明式表映射,它不仅包括 mapped_column()
对象,还包括关系和 SQL 表达式
from typing import List
from typing import Optional
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy import Text
from sqlalchemy.orm import column_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
firstname: Mapped[str] = mapped_column(String(50))
lastname: Mapped[str] = mapped_column(String(50))
fullname: Mapped[str] = column_property(firstname + " " + lastname)
addresses: Mapped[List["Address"]] = relationship(back_populates="user")
class Address(Base):
__tablename__ = "address"
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
email_address: Mapped[str]
address_statistics: Mapped[Optional[str]] = mapped_column(Text, deferred=True)
user: Mapped["User"] = relationship(back_populates="addresses")
上面的声明式表映射具有两个表,每个表都有一个指向另一个表的 relationship()
,以及一个由 column_property()
映射的简单 SQL 表达式,以及另一个 mapped_column()
,指示应根据 mapped_column.deferred
关键字定义的 “延迟” 方式加载。有关这些特定概念的更多文档,请参见 基本关系模式,使用 column_property,以及 限制通过列延迟加载的列。
属性可以使用 “混合表” 风格在声明式映射中指定;作为表直接组成部分的 Column
对象移动到 Table
定义中,但包括组合 SQL 表达式在内的所有其他内容仍然与类定义内联。需要直接引用 Column
的构造将根据 Table
对象引用它。为了说明使用混合表风格的上述映射
# mapping attributes using declarative with imperative table
# i.e. __table__
from sqlalchemy import Column, ForeignKey, Integer, String, Table, Text
from sqlalchemy.orm import column_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import deferred
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class User(Base):
__table__ = Table(
"user",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("name", String),
Column("firstname", String(50)),
Column("lastname", String(50)),
)
fullname = column_property(__table__.c.firstname + " " + __table__.c.lastname)
addresses = relationship("Address", back_populates="user")
class Address(Base):
__table__ = Table(
"address",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("user_id", ForeignKey("user.id")),
Column("email_address", String),
Column("address_statistics", Text),
)
address_statistics = deferred(__table__.c.address_statistics)
user = relationship("User", back_populates="addresses")
上述需要注意的事项
address
Table
包含一个名为address_statistics
的列,但是我们在相同的属性名称下重新映射此列,使其受deferred()
构造的控制。对于声明式表映射和混合表映射,当我们定义
ForeignKey
构造时,我们始终使用表名而不是映射的类名来命名目标表。当我们定义
relationship()
构造时,由于这些构造在两个映射类之间创建链接,其中一个类必须在另一个类之前定义,因此我们可以使用其字符串名称来引用远程类。此功能还扩展到relationship()
上指定的其他参数的区域,例如 “primary join” 和 “order by” 参数。有关此方面的详细信息,请参见 关系参数的延迟评估 部分。
使用声明式配置映射器选项¶
对于所有映射形式,类的映射都通过成为 Mapper
对象一部分的参数来配置。最终接收这些参数的函数是 Mapper
函数,这些参数从 registry
对象上定义的前端映射函数之一传递给它。
对于声明式映射形式,映射器参数使用 __mapper_args__
声明式类变量指定,该变量是一个字典,作为关键字参数传递给 Mapper
函数。一些示例
映射特定的主键列
下面的示例说明了 Mapper.primary_key
参数的声明式级别设置,该参数将特定列建立为 ORM 应考虑作为该类主键的一部分,独立于模式级别的主键约束
class GroupUsers(Base):
__tablename__ = "group_users"
user_id = mapped_column(String(40))
group_id = mapped_column(String(40))
__mapper_args__ = {"primary_key": [user_id, group_id]}
另请参阅
映射到显式主键列集 - 关于显式列作为主键列的 ORM 映射的进一步背景
版本 ID 列
下面的示例说明了 Mapper.version_id_col
和 Mapper.version_id_generator
参数的声明式级别设置,这些参数配置了 ORM 维护的版本计数器,该计数器在 工作单元 flush 进程中更新和检查
from datetime import datetime
class Widget(Base):
__tablename__ = "widgets"
id = mapped_column(Integer, primary_key=True)
timestamp = mapped_column(DateTime, nullable=False)
__mapper_args__ = {
"version_id_col": timestamp,
"version_id_generator": lambda v: datetime.now(),
}
另请参阅
配置版本计数器 - 关于 ORM 版本计数器功能的背景
单表继承
下面的示例说明了 Mapper.polymorphic_on
和 Mapper.polymorphic_identity
参数的声明式级别设置,这些参数在配置单表继承映射时使用
class Person(Base):
__tablename__ = "person"
person_id = mapped_column(Integer, primary_key=True)
type = mapped_column(String, nullable=False)
__mapper_args__ = dict(
polymorphic_on=type,
polymorphic_identity="person",
)
class Employee(Person):
__mapper_args__ = dict(
polymorphic_identity="employee",
)
另请参阅
单表继承 - 关于 ORM 单表继承映射功能的背景。
动态构建映射器参数¶
__mapper_args__
字典可以从类绑定的描述符方法而不是从固定字典生成,方法是使用 declared_attr()
构造。这对于为从表配置或映射类的其他方面以编程方式派生的映射器创建参数很有用。动态 __mapper_args__
属性在使用声明式 Mixin 或抽象基类时通常很有用。
例如,要从映射中省略任何具有特殊 Column.info
值的列,mixin 可以使用 __mapper_args__
方法,该方法从 cls.__table__
属性扫描这些列,并将它们传递给 Mapper.exclude_properties
集合
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import declared_attr
class ExcludeColsWFlag:
@declared_attr
def __mapper_args__(cls):
return {
"exclude_properties": [
column.key
for column in cls.__table__.c
if column.info.get("exclude", False)
]
}
class Base(DeclarativeBase):
pass
class SomeClass(ExcludeColsWFlag, Base):
__tablename__ = "some_table"
id = mapped_column(Integer, primary_key=True)
data = mapped_column(String)
not_needed = mapped_column(String, info={"exclude": True})
上面,ExcludeColsWFlag
mixin 提供了一个按类 __mapper_args__
钩子,它将扫描 Column
对象,这些对象包括传递给 Column.info
参数的键/值 'exclude': True
,然后将其字符串 “key” 名称添加到 Mapper.exclude_properties
集合中,这将阻止生成的 Mapper
考虑这些列进行任何 SQL 操作。
另请参阅
其他声明式映射指令¶
__declare_last__()
¶
__declare_last__()
钩子允许定义一个类级别函数,该函数在映射假定已完成且 “配置” 步骤已完成之后,由 MapperEvents.after_configured()
事件自动调用
class MyClass(Base):
@classmethod
def __declare_last__(cls):
""" """
# do something with mappings
__declare_first__()
¶
与 __declare_last__()
类似,但在映射器配置开始时通过 MapperEvents.before_configured()
事件调用
class MyClass(Base):
@classmethod
def __declare_first__(cls):
""" """
# do something before mappings are configured
metadata
¶
通常用于分配新 Table
的 MetaData
集合是与正在使用的 registry
对象关联的 registry.metadata
属性。当使用声明式基类(例如由 DeclarativeBase
超类生成的基类)以及诸如 declarative_base()
和 registry.generate_base()
等旧函数时,此 MetaData
通常也作为名为 .metadata
的属性存在于基类上,因此也通过继承存在于映射类上。声明式使用此属性(如果存在)来确定目标 MetaData
集合,如果不存在,则使用直接与 registry
关联的 MetaData
。
此属性也可以分配给,以便为单个基类和/或 registry
影响每个映射层次结构使用的 MetaData
集合。无论是否使用声明式基类,或者是否直接使用 registry.mapped()
装饰器,这都有效,从而允许诸如下一节 __abstract__ 中的每个抽象基类的元数据之类的模式。可以使用 registry.mapped()
来说明类似的模式,如下所示
reg = registry()
class BaseOne:
metadata = MetaData()
class BaseTwo:
metadata = MetaData()
@reg.mapped
class ClassOne:
__tablename__ = "t1" # will use reg.metadata
id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassTwo(BaseOne):
__tablename__ = "t1" # will use BaseOne.metadata
id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassThree(BaseTwo):
__tablename__ = "t1" # will use BaseTwo.metadata
id = mapped_column(Integer, primary_key=True)
另请参阅
__abstract__
¶
__abstract__
使声明式跳过为类生成表或映射器。可以将类添加到层次结构中,方式与 mixin 相同(请参见 Mixin 和自定义基类),从而允许子类仅从特殊类扩展
class SomeAbstractBase(Base):
__abstract__ = True
def some_helpful_method(self):
""" """
@declared_attr
def __mapper_args__(cls):
return {"helpful mapper arguments": True}
class MyMappedClass(SomeAbstractBase):
pass
__abstract__
的一种可能用途是为不同的基类使用不同的 MetaData
class Base(DeclarativeBase):
pass
class DefaultBase(Base):
__abstract__ = True
metadata = MetaData()
class OtherBase(Base):
__abstract__ = True
metadata = MetaData()
上面,从 DefaultBase
继承的类将使用一个 MetaData
作为表注册表,而从 OtherBase
继承的类将使用另一个 MetaData
。然后可以在不同的数据库中创建表本身
DefaultBase.metadata.create_all(some_engine)
OtherBase.metadata.create_all(some_other_engine)
另请参阅
使用 polymorphic_abstract 构建更深的层次结构 - “抽象” 映射类的另一种形式,适用于继承层次结构。
__table_cls__
¶
允许自定义用于生成 Table
的可调用对象/类。这是一个非常开放式的钩子,可以允许对在此处生成的 Table
进行特殊自定义
class MyMixin:
@classmethod
def __table_cls__(cls, name, metadata_obj, *arg, **kw):
return Table(f"my_{name}", metadata_obj, *arg, **kw)
上面的 mixin 将导致所有生成的 Table
对象都包含前缀 "my_"
,后跟通常使用 __tablename__
属性指定的名称。
__table_cls__
还支持返回 None
的情况,这会导致该类被视为相对于其子类的单表继承。这在某些自定义方案中可能很有用,以确定应基于表本身的参数进行单表继承,例如,如果不存在主键,则定义为单表继承
class AutoTable:
@declared_attr
def __tablename__(cls):
return cls.__name__
@classmethod
def __table_cls__(cls, *arg, **kw):
for obj in arg[1:]:
if (isinstance(obj, Column) and obj.primary_key) or isinstance(
obj, PrimaryKeyConstraint
):
return Table(*arg, **kw)
return None
class Person(AutoTable, Base):
id = mapped_column(Integer, primary_key=True)
class Employee(Person):
employee_name = mapped_column(String)
上面的 Employee
类将被映射为针对 Person
的单表继承;employee_name
列将作为 Person
表的成员添加。
flambé! 龙和 The Alchemist 图像设计由 Rotem Yaari 创建并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档最后生成时间:2025 年 3 月 11 日星期二下午 02:40:17 EDT