Функция with_polymorphic создает
специальный селектор, который позволяет
загружать объекты иерархии наследуемых
классов в одном запросе. Первым параметром
функция принимает базовый класс иерархии.
Вторым параметром передается список
наследуемых классов, которые нужно загрузить
одним запросом. Если вместо списка указать
строку '*', то будут загружены все
классы иерархии.
Обычно функция with_polymorphic
используется вместе с методом select.
Она помогает избежать проблемы N+1, когда
для каждого объекта иерархии выполняется
отдельный запрос к таблице наследника.
Синтаксис
with_polymorphic(base_class, [classes])
with_polymorphic(base_class, '*')
Пример
Давайте создадим иерархию классов, где
Article является базовым классом,
а TextArticle и NumArticle -
наследниками:
from sqlalchemy import create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.orm import with_polymorphic, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
status: Mapped[str]
type: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'article',
'polymorphic_on': type
}
class TextArticle(Article):
text: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'text_article'
}
class NumArticle(Article):
num: Mapped[int]
__mapper_args__ = {
'polymorphic_identity': 'num_article'
}
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Пример
Теперь загрузим все объекты иерархии
одним запросом с помощью функции
with_polymorphic:
<+python+>
from sqlalchemy import create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.orm import with_polymorphic, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
type: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'article',
'polymorphic_on': type
}
class TextArticle(Article):
text: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'text_article'
}
class NumArticle(Article):
num: Mapped[int]
__mapper_args__ = {
'polymorphic_identity': 'num_article'
}
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(TextArticle(title='article 1', text='some text'))
session.add(NumArticle(title='article 2', num=42))
session.commit()
poly = with_polymorphic(Article, [TextArticle, NumArticle])
stmt = select(poly)
res = session.scalars(stmt).all()
for obj in res:
print(type(obj).__name__, obj.title)
<-python+>
Результат выполнения кода:
"TextArticle article 1"
"NumArticle article 2"
Пример
Если вместо списка классов передать
строку '*', то будут загружены
все классы иерархии:
<+python+>
from sqlalchemy import create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.orm import with_polymorphic, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
type: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'article',
'polymorphic_on': type
}
class TextArticle(Article):
text: Mapped[str]
__mapper_args__ = {
'polymorphic_identity': 'text_article'
}
class NumArticle(Article):
num: Mapped[int]
__mapper_args__ = {
'polymorphic_identity': 'num_article'
}
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(TextArticle(title='article 1', text='some text'))
session.add(NumArticle(title='article 2', num=42))
session.commit()
poly = with_polymorphic(Article, '*')
stmt = select(poly)
res = session.scalars(stmt).all()
for obj in res:
print(type(obj).__name__, obj.title)
<-python+>
Результат выполнения кода:
<+python+>
"TextArticle article 1"
"NumArticle article 2"
<-python+>
Смотрите также
-
функцию
select,
которая создает SELECT-запрос
-
функцию
aliased,
которая создает псевдоним для класса
-
функцию
values,
которая создает конструкцию VALUES
-
функцию
union,
которая объединяет результаты запросов