Атрибут polymorphic_on
Атрибут polymorphic_on класса Mapper указывает
на колонку таблицы, значение которой используется для
определения конкретного класса-наследника при загрузке
строки из базы данных. Обычно это строковая колонка,
хранящая идентификатор подкласса (например, 'article'
или 'user'). Атрибут задается при настройке
отображения через __mapper_args__ и работает в паре
с атрибутом polymorphic_identity, который задает
значение для каждого класса.
Синтаксис
class Parent(Base):
__tablename__ = 'articles'
__mapper_args__ = {
'polymorphic_on': column_name,
'polymorphic_identity': 'value'
}
Пример
Давайте создадим иерархию классов, где базовый класс
Article использует колонку status для
различения наследников:
from sqlalchemy import create_engine, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
engine = create_engine('sqlite:///:memory:')
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(50))
__mapper_args__ = {
'polymorphic_on': status,
'polymorphic_identity': 'article'
}
class NewsArticle(Article):
__mapper_args__ = {
'polymorphic_identity': 'news'
}
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(title='article 1', status='article'))
session.add(NewsArticle(title='article 2', status='news'))
session.commit()
res = session.query(Article).all()
for obj in res:
print(type(obj).__name__, obj.title, obj.status)
Результат выполнения кода:
Article article 1 article
NewsArticle article 2 news
Пример
Давайте посмотрим, какой SQL-запрос генерирует
SQLAlchemy при использовании polymorphic_on:
from sqlalchemy import create_engine, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
engine = create_engine('sqlite:///:memory:', echo=True)
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(50))
__mapper_args__ = {
'polymorphic_on': status,
'polymorphic_identity': 'article'
}
class NewsArticle(Article):
__mapper_args__ = {
'polymorphic_identity': 'news'
}
Base.metadata.create_all(engine)
with Session(engine) as session:
res = session.query(Article).all()
print(res)
Итоговый SQL запрос:
SELECT articles.id AS articles_id, articles.title AS articles_title, articles.status AS articles_status
FROM articles
Смотрите также
-
класс
Mapper,
который управляет отображением класса на таблицу -
атрибут
polymorphic_identity,
который задает значение для каждого класса-наследника -
атрибут
columns,
который хранит коллекцию колонок маппера -
атрибут
relationships,
который содержит связи между моделями