РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
527 of 711 menu

Значение lazy joined

Значение lazy='joined' передается в параметр lazy отношения relationship и включает жадную загрузку связанных объектов. При выборке родителя SQLAlchemy сразу добавляет к основному запросу LEFT OUTER JOIN и загружает дочерние записи в том же запросе. Это избавляет от эффекта N+1, когда для каждой родительской строки выполняется отдельный дополнительный запрос.

Отношение объявляется через функцию relationship, в которой первым параметром передается имя связанного класса, а параметр lazy принимает строку 'joined'. По умолчанию для отношений используется значение 'select', то есть ленивая загрузка отдельными запросами.

Синтаксис

relationship(ClassName, lazy='joined')

Пример

Давайте создадим две связанные модели и настроим жадную загрузку через lazy='joined':

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='joined') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] 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', articles=[Article(title='article')]) session.add(user) session.commit() res = session.query(User).all() print(res[0].articles)

Результат выполнения кода:

[Article(id=1, title='article', user_id=1)]

Пример

Давайте включим вывод SQL-запросов и посмотрим, что связанные объекты загружаются одним запросом с LEFT OUTER JOIN:

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='joined') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) engine = create_engine('sqlite:///:memory:', echo=True) Base.metadata.create_all(engine) with Session(engine) as session: user = User(name='user', articles=[Article(title='article')]) session.add(user) session.commit() res = session.query(User).all() print(res[0].articles[0].title)

Итоговый SQL запрос:

SELECT users.id AS users_id, users.name AS users_name, articles_1.id AS articles_1_id, articles_1.title AS articles_1_title, articles_1.user_id AS articles_1_user_id FROM users LEFT OUTER JOIN articles AS articles_1 ON users.id = articles_1.user_id

Пример

Давайте убедимся, что при обращении к связи после основного запроса дополнительный SQL не выполняется:

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='joined') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) engine = create_engine('sqlite:///:memory:', echo=True) Base.metadata.create_all(engine) with Session(engine) as session: user = User(name='user', articles=[Article(title='article')]) session.add(user) session.commit() session.expire_all() res = session.query(User).all() print('loaded:', res[0].articles[0].title)

В логе видно только один SELECT с джойном, а строка loaded: article выводится без дополнительного запроса:

"loaded: article"

Смотрите также

  • функцию relationship,
    которая настраивает связи между моделями
  • значение lazy.select,
    которое включает ленивую загрузку отдельным запросом
  • функцию joinedload,
    которая задает жадную загрузку на уровне запроса
  • функцию selectinload,
    которая загружает связи через отдельный IN-запрос
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить