Декларативные стили отображения

Как было представлено в Декларативное отображение, Декларативное отображение является типичным способом построения отображений в современной 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 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 служит базой для новых классов, которые должны быть отображены, как выше построены новые отображенные классы User и Address.

Для каждого построенного подкласса тело класса затем следует декларативному подходу к отображению, который определяет как Table, так и Mapper объект за кулисами, которые составляют полное отображение.

См.также

Конфигурация таблицы с помощью декларативного - описывает, как указать компоненты генерируемого отображенного Table, включая примечания и опции по использованию конструкции mapped_column() и ее взаимодействию с типом аннотации Mapped

Конфигурация картографа с помощью декларативного метода - описывает все остальные аспекты конфигурации ORM mapper в рамках Declarative, включая 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",
    }

Оба стиля конфигурации таблиц declarative table и imperative table могут быть использованы либо с декларативным базовым стилем, либо с декоративным стилем декларативного отображения.

Декораторная форма отображения полезна при комбинировании декларативного отображения SQLAlchemy с другими системами инструментации классов, такими как dataclasses и attrs, хотя обратите внимание, что SQLAlchemy 2.0 теперь имеет интеграцию dataclasses с декларативными базовыми классами.

Вернуться на верх