声明式映射风格

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

使用声明式基类

最常见的做法是通过子类化 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 被构建。

对于每个构建的子类,类的主体随后遵循声明式映射方法,该方法在幕后定义了 TableMapper 对象,它们构成了完整的映射。

另请参阅

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

使用声明式配置 Mapper - 描述了声明式中 ORM Mapper 配置的所有其他方面,包括 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 功能。