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

Как было представлено в Декларативное отображение, Декларативное отображение является типичным способом построения отображений в современной SQLAlchemy. В этом разделе будет представлен обзор форм, которые могут быть использованы для конфигурации декларативного маппинга.

Использование сгенерированного базового класса

Наиболее распространенный подход заключается в создании «базового» класса с помощью функции declarative_base():

from sqlalchemy.orm import declarative_base

# declarative base class
Base = declarative_base()

Декларативный базовый класс также может быть создан из существующего registry, используя метод registry.generate_base():

from sqlalchemy.orm import registry

reg = registry()

# declarative base class
Base = reg.generate_base()

При использовании декларативного базового класса новые сопоставленные классы объявляются как подклассы базового:

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base

# declarative base class
Base = declarative_base()


# an example mapping using the base
class User(Base):
    __tablename__ = "user"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    nickname = Column(String)

Выше функция declarative_base() возвращает новый базовый класс, от которого могут наследоваться новые сопоставляемые классы, как выше строится новый сопоставляемый класс User.

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

Создание явного базиса нединамически (для использования с mypy, аналогично)

SQLAlchemy включает Mypy plugin, который автоматически подстраивается под динамически генерируемый класс Base, предоставляемый такими функциями SQLAlchemy, как declarative_base(). Только для SQLAlchemy 1.4 серии этот плагин работает вместе с новым набором заглушек для типизации, опубликованным в sqlalchemy2-stubs.

Когда этот плагин не используется, или при использовании других инструментов PEP 484, которые могут не знать, как интерпретировать этот класс, декларативный базовый класс может быть создан в полностью явном виде с помощью DeclarativeMeta непосредственно следующим образом:

from sqlalchemy.orm import registry
from sqlalchemy.orm.decl_api import DeclarativeMeta

mapper_registry = registry()


class Base(metaclass=DeclarativeMeta):
    __abstract__ = True

    registry = mapper_registry
    metadata = mapper_registry.metadata

    __init__ = mapper_registry.constructor

Приведенный выше Base эквивалентен созданному методом registry.generate_base() и будет полностью понятен инструментам анализа типов без использования плагинов.

См.также

Mypy / Pep-484 Поддержка отображений ORM - справочная информация о плагине Mypy, который автоматически применяет описанную выше структуру при запуске Mypy.

Декларативное отображение с использованием декоратора (без декларативной базы)

Альтернативой использованию «декларативного базового» класса является применение декларативного отображения к классу в явном виде, используя либо императивную технику, аналогичную «классическому» отображению, либо более лаконично - с помощью декоратора. Функция registry.mapped() является декоратором класса, который может быть применен к любому классу Python без иерархии. В противном случае класс Python конфигурируется в декларативном стиле обычным образом:

from sqlalchemy import Column, ForeignKey, Integer, String, Text
from sqlalchemy.orm import registry, relationship

mapper_registry = registry()


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

    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", back_populates="user")


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

    id = Column(Integer, primary_key=True)
    user_id = Column(ForeignKey("user.id"))
    email_address = Column(String)

    user = relationship("User", back_populates="addresses")

Выше, тот же самый registry, который мы используем для создания декларативного базового класса через его метод registry.generate_base(), может также применять отображение декларативного стиля к классу без использования базы. При использовании вышеуказанного стиля отображение определенного класса будет только происходить, если декоратор применяется непосредственно к этому классу. Для отображений наследования декоратор должен быть применен к каждому подклассу:

from sqlalchemy.orm import registry

mapper_registry = registry()


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

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

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


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

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

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

Оба стиля декларативного отображения «декларативная таблица» и «императивная таблица» могут быть использованы с вышеуказанным стилем отображения.

Декораторная форма отображения особенно полезна при комбинировании декларативного отображения SQLAlchemy с другими формами объявления классов, в частности с модулем Python dataclasses. См. следующий раздел.

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