Декларативные расширения¶
Расширения, специфичные для 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