声明式映射样式

正如在 声明式映射 中介绍的,声明式映射是现代 SQLAlchemy 中构建映射的典型方式。本节将概述可用于声明式映射器配置的形式。

使用声明式基类

最常见的方法是通过子类化 DeclarativeBase 超类来生成“声明式基类”

from sqlalchemy.orm import DeclarativeBase


# declarative base class
class Base(DeclarativeBase):
    pass

声明式基类也可以通过将现有的 registry 分配为名为 registry 的类变量来创建

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import registry

reg = registry()


# declarative base class
class Base(DeclarativeBase):
    registry = reg

在版本 2.0 中更改: DeclarativeBase 超类取代了 declarative_base() 函数和 registry.generate_base() 方法的使用;超类方法与 PEP 484 工具集成,无需使用插件。请参阅 ORM 声明式模型 以获取迁移说明。

使用声明式基类,新的映射类声明为基类的子类

from datetime import datetime
from typing import List
from typing import Optional

from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
from sqlalchemy import String
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_column(Integer, primary_key=True)
    name: Mapped[str]
    fullname: Mapped[Optional[str]]
    nickname: Mapped[Optional[str]] = mapped_column(String(64))
    create_date: Mapped[datetime] = mapped_column(insert_default=func.now())

    addresses: Mapped[List["Address"]] = relationship(back_populates="user")


class Address(Base):
    __tablename__ = "address"

    id = mapped_column(Integer, primary_key=True)
    user_id = mapped_column(ForeignKey("user.id"))
    email_address: Mapped[str]

    user: Mapped["User"] = relationship(back_populates="addresses")

上面,Base 类作为要映射的新类的基类,如上所示,新的映射类 UserAddress 被构造。

对于构造的每个子类,类的正文随后遵循声明式映射方法,该方法在幕后定义了 Table 以及 Mapper 对象,它们构成完整的映射。

另请参阅

使用声明式配置表 - 描述如何指定要生成的映射 Table 的组件,包括关于 mapped_column() 构造的使用以及它如何与 Mapped 注解类型交互的注释和选项

使用声明式配置映射器 - 描述声明式中 ORM 映射器配置的所有其他方面,包括 relationship() 配置、SQL 表达式和 Mapper 参数

使用装饰器的声明式映射(无声明式基类)

除了使用“声明式基类”之外,另一种方法是显式地将声明式映射应用于类,使用类似于“经典”映射的命令式技术,或者更简洁地使用装饰器。registry.mapped() 函数是一个类装饰器,可以应用于任何没有层级结构的 Python 类。Python 类的其他配置通常采用声明式样式。

下面的示例设置了与上一节中看到的相同的映射,使用 registry.mapped() 装饰器而不是使用 DeclarativeBase 超类

from datetime import datetime
from typing import List
from typing import Optional

from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship

mapper_registry = registry()


@mapper_registry.mapped
class User:
    __tablename__ = "user"

    id = mapped_column(Integer, primary_key=True)
    name: Mapped[str]
    fullname: Mapped[Optional[str]]
    nickname: Mapped[Optional[str]] = mapped_column(String(64))
    create_date: Mapped[datetime] = mapped_column(insert_default=func.now())

    addresses: Mapped[List["Address"]] = relationship(back_populates="user")


@mapper_registry.mapped
class Address:
    __tablename__ = "address"

    id = mapped_column(Integer, primary_key=True)
    user_id = mapped_column(ForeignKey("user.id"))
    email_address: Mapped[str]

    user: Mapped["User"] = relationship(back_populates="addresses")

当使用上述样式时,只有当装饰器直接应用于特定类时,该类的映射才会继续。对于继承映射(在 映射类继承层级 中详细描述),装饰器应应用于要映射的每个子类

from sqlalchemy.orm import registry

mapper_registry = registry()


@mapper_registry.mapped
class Person:
    __tablename__ = "person"

    person_id = mapped_column(Integer, primary_key=True)
    type = mapped_column(String, nullable=False)

    __mapper_args__ = {
        "polymorphic_on": type,
        "polymorphic_identity": "person",
    }


@mapper_registry.mapped
class Employee(Person):
    __tablename__ = "employee"

    person_id = mapped_column(ForeignKey("person.person_id"), primary_key=True)

    __mapper_args__ = {
        "polymorphic_identity": "employee",
    }

声明式表命令式表 表配置样式可以与声明式基类或声明式映射的装饰器样式一起使用。

当将 SQLAlchemy 声明式映射与其他类检测系统(如 dataclassesattrs)结合使用时,装饰器形式的映射非常有用,但请注意,SQLAlchemy 2.0 现在也具有与声明式基类的 dataclasses 集成。