Значение lazy select
Значение lazy со строкой 'select' задает
стратегию отложенной загрузки связанных объектов
в SQLAlchemy. Это поведение используется по умолчанию
для связей relationship. Связанные строки
не загружаются вместе с родительским объектом.
Вместо этого при первом обращении к атрибуту связи
SQLAlchemy отправляет отдельный SELECT запрос
и только затем возвращает результат. Значение
lazy принимает строку 'select'
и передается в параметр lazy функции
relationship. Такой подход экономит память
при работе с большим количеством родителей,
если связанные объекты нужны не всегда.
Синтаксис
relationship(..., lazy='select')
Пример
Давайте создадим две модели, связанные отношением
один-ко-многим, и укажем для связи стратегию
lazy со значением 'select':
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
articles: Mapped[list['Article']] = relationship(lazy='select')
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(name='user')
user.articles = [
Article(title='article 1', text='text 1', status='new', num=1),
Article(title='article 2', text='text 2', status='new', num=2),
]
session.add(user)
session.commit()
Теперь при обращении к атрибуту articles
SQLAlchemy выполнит отдельный запрос только в этот момент:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from models import User
engine = create_engine('sqlite:///:memory:')
with Session(engine) as session:
user = session.get(User, 1)
print('before access')
titles = [a.title for a in user.articles]
print(titles)
Результат выполнения кода:
"before access"
['article 1', 'article 2']
Пример
Давайте посмотрим, какие SQL-запросы отправляются
при стратегии lazy со значением 'select'.
Первый запрос загружает родителя, второй - связанные строки:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from models import User
engine = create_engine('sqlite:///:memory:', echo=True)
with Session(engine) as session:
user = session.get(User, 1)
titles = [a.title for a in user.articles]
print(titles)
Итоговый SQL запрос для связанных строк:
SELECT articles.id AS articles_id, articles.title AS articles_title, articles.text AS articles_text, articles.status AS articles_status, articles.num AS articles_num, articles.user_id AS articles_user_id
FROM articles
WHERE ? = articles.user_id
Пример
Значение lazy можно указать не только
в модели, но и переопределить на уровне запроса
методом options:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, selectinload
from models import User
from sqlalchemy import select
engine = create_engine('sqlite:///:memory:')
with Session(engine) as session:
stmt = select(User).options(selectinload(User.articles))
user = session.scalars(stmt).first()
titles = [a.title for a in user.articles]
print(titles)
Результат выполнения кода:
['article 1', 'article 2']
Смотрите также
-
функцию
relationship,
которая настраивает связи между моделями -
значение
lazy selectin,
которое загружает связи отдельным IN-запросом -
значение
lazy joined,
которое загружает связи через JOIN -
значение
lazyload,
которое включает отложенную загрузку явно