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