SQLAlchemy 2.0 文档
使用声明式配置映射器¶
部分 映射类基本组件 讨论了 Mapper
结构的通用配置元素,该结构定义了如何将特定用户定义的类映射到数据库表或其他 SQL 结构。以下部分介绍了声明式系统如何构建 Mapper
的具体细节。
使用声明式定义映射属性¶
在 使用声明式配置表 中给出的示例说明了针对表绑定列的映射,使用了 mapped_column()
结构。除了表绑定列之外,还可以配置 ORM 映射结构的几种其他类型,最常见的是 relationship()
结构。其他类型的属性包括使用 column_property()
结构定义的 SQL 表达式,以及使用 composite()
结构进行的多列映射。
虽然 命令式映射 使用 属性 字典来建立所有映射的类属性,但在声明式映射中,这些属性都在类定义中内联定义,在声明式表映射的情况下,这些属性都在 Column
对象内联定义,这些对象将用于生成 Table
对象。
使用 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")
上面需要注意的事项
地址
Table
包含一个名为address_statistics
的列,但我们将此列重新映射到相同的属性名称下,使其处于deferred()
结构的控制之下。在声明式表和混合表映射中,当我们定义
ForeignKey
结构时,我们始终使用**表名**而不是映射的类名来命名目标表。当我们定义
relationship()
结构时,因为这些结构在两个映射的类之间创建了连接,其中一个必须在另一个之前定义,我们可以使用字符串名称引用远程类。此功能还扩展到relationship()
上指定的其他参数,例如“主连接”和“排序”参数。有关此方面的详细信息,请参阅部分 关系参数的延迟评估。
使用声明式配置映射器选项¶
对于所有映射形式,类的映射都是通过参数配置的,这些参数成为 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 维护的版本计数器,该计数器在 工作单元 刷新过程中更新和检查
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()
结构从类绑定描述符方法生成,而不是从固定字典生成。这对于创建从表配置或映射类的其他方面以编程方式派生的映射器参数很有用。当使用声明式 Mixin 或抽象基类时,动态 __mapper_args__
属性通常会有用。
例如,要从映射中省略具有特殊 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
,然后将其字符串“键”名称添加到 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
。
此属性也可以被分配以影响 MetaData
集合,以便在单个基类和/或 registry
的每个映射层次结构中使用。这将影响是否使用声明式基类或是否直接使用 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
继承的类将使用另一个注册表。然后,这些表可以在不同的数据库中创建
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é! 龙和炼金术士 图像设计由 Rotem Yaari 创建并慷慨捐赠。
使用 Sphinx 7.2.6 创建。 文档最后生成时间:2024 年 11 月 8 日星期五上午 8:41:19 EST