Функция deferred
Функция deferred помечает столбец
модели как отложенный. Такой столбец
не загружается из базы данных сразу
при выборке объекта, а подгружается
только при первом обращении к нему.
Первым параметром передаётся столбец
модели, который нужно сделать отложенным.
Вторым необязательным параметром
передаётся группа загрузки group,
позволяющая откладывать сразу несколько
столбцов. Третьим необязательным
параметром передаётся флаг raiseload,
который запрещает обращение к столбцу
до его явной загрузки.
Синтаксис
deferred(column, [group], [raiseload])
Пример
Давайте создадим модель Article
с отложенным столбцом text:
from sqlalchemy import create_engine, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, deferred, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = deferred(mapped_column(Text))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1', text='long text content')
session.add(article)
session.commit()
res = session.get(Article, 1)
print(res.title)
Результат выполнения кода:
"article 1"
Пример
Давайте посмотрим, какой SQL-запрос выполняется при загрузке объекта с отложенным столбцом:
from sqlalchemy import create_engine, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, deferred, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = deferred(mapped_column(Text))
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1', text='long text content')
session.add(article)
session.commit()
res = session.get(Article, 1)
print(res.title)
Итоговый SQL запрос:
SELECT articles.id AS articles_id, articles.title AS articles_title
FROM articles
WHERE articles.id = ?
Как видно из запроса, столбец text
не был выбран при загрузке объекта.
Он будет загружен отдельным запросом
при первом обращении к атрибуту.
Пример
Давайте обратимся к отложенному столбцу и посмотрим, какой запрос выполнится при этом:
from sqlalchemy import create_engine, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, deferred, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = deferred(mapped_column(Text))
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1', text='long text content')
session.add(article)
session.commit()
res = session.get(Article, 1)
print(res.text)
Итоговый SQL запрос:
SELECT articles.text AS articles_text
FROM articles
WHERE articles.id = ?
При обращении к атрибуту text
SQLAlchemy выполнил дополнительный
запрос для его загрузки.
Пример
Давайте сгруппируем несколько
отложенных столбцов с помощью
параметра group:
from sqlalchemy import create_engine, String, Text, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, deferred, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = deferred(mapped_column(Text), group='content')
num: Mapped[int] = deferred(mapped_column(Integer), group='content')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1', text='long text', num=10)
session.add(article)
session.commit()
res = session.get(Article, 1)
print(res.title)
Результат выполнения кода:
"article 1"
Пример
Давайте загрузим отложенную группу
столбцов явно с помощью опции
undefer_group:
from sqlalchemy import create_engine, String, Text, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, deferred, Session
from sqlalchemy.orm import undefer_group
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = deferred(mapped_column(Text), group='content')
num: Mapped[int] = deferred(mapped_column(Integer), group='content')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1', text='long text', num=10)
session.add(article)
session.commit()
res = session.get(Article, 1, options=[undefer_group('content')])
print(res.text, res.num)
Результат выполнения кода:
"long text 10"
Смотрите также
-
функцию
column_property,
которая добавляет вычисляемый столбец в модель -
функцию
query_expression,
которая добавляет выражение запроса в модель -
функцию
composite,
которая объединяет несколько столбцов в один атрибут -
функцию
mapped_column,
которая настраивает столбец модели