Декларативные расширения¶
Расширения, специфичные для API отображения Declarative.
Изменено в версии 1.4: Большая часть расширения Declarative теперь интегрирована в SQLAlchemy ORM и импортируется из пространства имен sqlalchemy.orm. Новую документацию смотрите по адресу Декларативное отображение. Обзор изменений приведен в разделе Декларативность теперь интегрирована в ORM с новыми возможностями.
| Object Name | Description |
|---|---|
Вспомогательный класс для «конкретных» декларативных отображений. |
|
Вспомогательный класс для «конкретных» декларативных отображений. |
|
Вспомогательный класс для построения отображений на основе отложенного шага отражения. |
- class sqlalchemy.ext.declarative.AbstractConcreteBase¶
Вспомогательный класс для «конкретных» декларативных отображений.
AbstractConcreteBaseбудет автоматически использовать функциюpolymorphic_union()для всех таблиц, отображенных как подкласс на этот класс. Функция вызывается через функцию__declare_first__(), которая по сути является крючком для событияbefore_configured().AbstractConcreteBaseприменяетMapperдля своего непосредственно наследуемого класса, как и для любого другого декларативно сопоставленного класса. ОднакоMapperне сопоставляется с каким-либо конкретным объектомTable. Вместо этого он сопоставляется непосредственно с «полиморфным» selectable, порожденнымpolymorphic_union(), и не выполняет никаких операций сохранения самостоятельно. Сравните сConcreteBase, который сопоставляет свой непосредственно наследуемый класс с реальнымTable, хранящим строки напрямую.Примечание
AbstractConcreteBaseзадерживает создание маппера базового класса до тех пор, пока не будут определены все подклассы, поскольку необходимо создать отображение на selectable, включающее все таблицы подклассов. Для этого необходимо дождаться события mapper configuration, после чего просмотреть все сконфигурированные подклассы и создать отображение, которое будет запрашивать сразу все подклассы.Хотя обычно это событие вызывается автоматически, в случае
AbstractConcreteBaseможет потребоваться его явный вызов после определения всех отображений подклассов, если первой операцией будет запрос к этому базовому классу. Для этого после настройки всех нужных классов можно вызвать методregistry.configure()на используемомregistry, который доступен по отношению к конкретному декларативному базовому классу:Base.registry.configure()
Пример:
from sqlalchemy.orm import DeclarativeBase from sqlalchemy.ext.declarative import AbstractConcreteBase class Base(DeclarativeBase): pass class Employee(AbstractConcreteBase, Base): pass class Manager(Employee): __tablename__ = 'manager' employee_id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { 'polymorphic_identity':'manager', 'concrete':True } Base.registry.configure()
Абстрактный базовый класс обрабатывается в declarative особым образом: во время конфигурирования класса он ведет себя как декларативный миксин или базовый класс
__abstract__. После того как классы сконфигурированы и созданы отображения, он сам становится отображаемым, но после всех своих потомков. Это очень уникальная система отображения, не встречающаяся ни в одной другой возможности SQLAlchemy API.Используя этот подход, мы можем задавать столбцы и свойства, которые будут иметь место у отображаемых подклассов, так, как это обычно делается в Миксины и пользовательские базовые классы:
from sqlalchemy.ext.declarative import AbstractConcreteBase class Company(Base): __tablename__ = 'company' id = Column(Integer, primary_key=True) class Employee(AbstractConcreteBase, Base): strict_attrs = True employee_id = Column(Integer, primary_key=True) @declared_attr def company_id(cls): return Column(ForeignKey('company.id')) @declared_attr def company(cls): return relationship("Company") class Manager(Employee): __tablename__ = 'manager' name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { 'polymorphic_identity':'manager', 'concrete':True } Base.registry.configure()
Однако, когда мы используем наши отображения, и
Manager, иEmployeeбудут иметь независимо используемый атрибут.company:session.execute( select(Employee).filter(Employee.company.has(id=5)) )
- Параметры:
strict_attrs – при указании на базовый класс включается «строгий» режим работы с атрибутами, который пытается ограничить отображаемые в ORM атрибуты базового класса только теми, которые присутствуют непосредственно, сохраняя при этом «полиморфное» поведение при загрузке. … версия добавлена:: 2.0
Классическая подпись.
класс
sqlalchemy.ext.declarative.AbstractConcreteBase(sqlalchemy.ext.declarative.extensions.ConcreteBase)
- class sqlalchemy.ext.declarative.ConcreteBase¶
Вспомогательный класс для «конкретных» декларативных отображений.
ConcreteBaseбудет автоматически использовать функциюpolymorphic_union()для всех таблиц, отображенных как подкласс на этот класс. Функция вызывается через функцию__declare_last__(), которая по сути является крючком для событияafter_configured().ConcreteBaseсоздает таблицу отображения для самого класса. Сравните сAbstractConcreteBase, который этого не делает.Пример:
from sqlalchemy.ext.declarative import ConcreteBase class Employee(ConcreteBase, Base): __tablename__ = 'employee' employee_id = Column(Integer, primary_key=True) name = Column(String(50)) __mapper_args__ = { 'polymorphic_identity':'employee', 'concrete':True} class Manager(Employee): __tablename__ = 'manager' employee_id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { 'polymorphic_identity':'manager', 'concrete':True}
По умолчанию имя столбца-дискриминатора, используемого в
polymorphic_union(), имеет имяtype. Для того чтобы удовлетворить требованиям отображения, в котором реальный столбец в отображаемой таблице уже имеет имяtype, имя дискриминатора может быть сконфигурировано путем установки атрибута_concrete_discriminator_name:class Employee(ConcreteBase, Base): _concrete_discriminator_name = '_concrete_discriminator'
Добавлено в версии 1.3.19: В
ConcreteBaseдобавлен атрибут_concrete_discriminator_nameдля того, чтобы можно было настроить имя столбца виртуального дискриминатора.Изменено в версии 1.4.2: Атрибут
_concrete_discriminator_nameнеобходимо поместить только в самый базовый класс, чтобы он корректно действовал для всех подклассов. При конфликте имен отображаемых столбцов с именами дискриминаторов теперь выдается явное сообщение об ошибке, тогда как в версии 1.3.x выдавались предупреждения, а затем формировался неиспользуемый запрос.
- class sqlalchemy.ext.declarative.DeferredReflection¶
Вспомогательный класс для построения отображений на основе отложенного шага отражения.
Обычно декларативное отображение можно использовать с отражением, задав в качестве атрибута
__table__декларативного класса объектTable, использующий autoload_with=engine. Оговорка заключается в том, чтоTableдолжен быть полностью отражен или, по крайней мере, иметь колонку первичного ключа на момент построения обычного декларативного отображения, то естьEngineдолжен быть доступен во время объявления класса.Миксин
DeferredReflectionпереносит построение отображателей на более поздний момент, после вызова определенного метода, который сначала отражает все созданные на данный момент объектыTable. Классы могут определять его следующим образом:from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import DeferredReflection Base = declarative_base() class MyClass(DeferredReflection, Base): __tablename__ = 'mytable'
Выше указано, что
MyClassеще не сопоставлен. После определения ряда классов описанным выше способом все таблицы могут быть отражены и созданы отображения с помощьюprepare():engine = create_engine("someengine://...") DeferredReflection.prepare(engine)
Миксин
DeferredReflectionможет применяться к отдельным классам, использоваться в качестве основы для декларативной базы или использоваться в пользовательском абстрактном классе. Использование абстрактной базы позволяет подготовить только подмножество классов для конкретного шага подготовки, что необходимо для приложений, использующих более одного движка. Например, если приложение имеет два движка, то можно использовать две базы и готовить каждую отдельно, например:class ReflectedOne(DeferredReflection, Base): __abstract__ = True class ReflectedTwo(DeferredReflection, Base): __abstract__ = True class MyClass(ReflectedOne): __tablename__ = 'mytable' class MyOtherClass(ReflectedOne): __tablename__ = 'myothertable' class YetAnotherClass(ReflectedTwo): __tablename__ = 'yetanothertable' # ... etc.
Выше иерархии классов для
ReflectedOneиReflectedTwoмогут быть настроены отдельно:ReflectedOne.prepare(engine_one) ReflectedTwo.prepare(engine_two)
Members
См.также
Использование DeferredReflection - в разделе Конфигурация таблицы с помощью декларативного.
-
classmethod
sqlalchemy.ext.declarative.DeferredReflection.prepare(bind: Union[Engine, Connection], **reflect_kw: Any) None¶ Отразить все
Tableобъекты для всех текущихDeferredReflectionподклассов- Параметры:
bind –
EngineилиConnectionв экземпляре ..versionchanged:: 2.0.16 также принимаетсяConnection.**reflect_kw – дополнительные ключевые аргументы, передаваемые в
MetaData.reflect(), напримерMetaData.reflect.views. … versionadded:: 2.0.16
-
classmethod