Функция load_only
Функция load_only указывает ORM загружать
только перечисленные колонки сущности. Остальные
атрибуты помечаются как отложенные и загружаются
отдельным запросом при первом обращении. Это
позволяет сократить объем данных, передаваемых
из базы, особенно когда модель содержит
тяжелые текстовые или бинарные поля. Функция
принимает один или несколько атрибутов-колонок
в качестве позиционных аргументов. Применяется
в опциях запроса через метод options.
Синтаксис
from sqlalchemy.orm import load_only
load_only(*attrs)
Пример
Давайте создадим модель статьи и загрузим
только колонки id и title:
from sqlalchemy import create_engine, String, Text, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session, load_only
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] = mapped_column(Text)
status: Mapped[str] = mapped_column(String(50))
num: Mapped[int] = mapped_column(Integer)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(
title='article',
text='long text content',
status='published',
num=1
))
session.commit()
res = session.query(Article).options(
load_only(Article.id, Article.title)
).first()
print(res.id)
print(res.title)
Результат выполнения кода:
"1"
"article"
Итоговый SQL запрос:
SELECT articles.id AS articles_id, articles.title AS articles_title
FROM articles
Пример
Давайте обратимся к отложенному атрибуту
text и посмотрим, как ORM догружает
его отдельным запросом:
from sqlalchemy import create_engine, String, Text, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session, load_only
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] = mapped_column(Text)
status: Mapped[str] = mapped_column(String(50))
num: Mapped[int] = mapped_column(Integer)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(
title='article',
text='long text content',
status='published',
num=1
))
session.commit()
res = session.query(Article).options(
load_only(Article.id, Article.title)
).first()
print(res.text)
Результат выполнения кода:
"long text content"
Итоговый SQL запрос при обращении к text:
SELECT articles.text AS articles_text
FROM articles
WHERE articles.id = 1
Пример
Давайте применим load_only вместе с
raiseload, чтобы запретить ленивую догрузку
остальных полей:
from sqlalchemy import create_engine, String, Text, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session, load_only, raiseload
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] = mapped_column(Text)
status: Mapped[str] = mapped_column(String(50))
num: Mapped[int] = mapped_column(Integer)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(
title='article',
text='long text content',
status='published',
num=1
))
session.commit()
res = session.query(Article).options(
load_only(Article.id, Article.title),
raiseload('*')
).first()
print(res.id)
print(res.title)
try:
print(res.status)
except Exception as e:
print(type(e).__name__)
Результат выполнения кода:
"1"
"article"
"InvalidRequestError"