Декларативные стили отображения¶
Как было представлено в Декларативное отображение, Декларативное отображение является типичным способом построения отображений в современной 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. См. следующий раздел.