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

Функция joinedload

Функция joinedload выполняет жадную загрузку связанных объектов с помощью SQL-оператора JOIN. Первым параметром функция принимает атрибут связи, который нужно загрузить. Дополнительные параметры позволяют управлять стратегией загрузки для вложенных связей.

Основное преимущество joinedload заключается в том, что связанные данные извлекаются одним запросом вместе с основным объектом. Это избавляет от проблемы N+1 запросов, когда для каждого родительского объекта выполняется отдельный запрос на загрузку связи.

Синтаксис

joinedload(attribute, [innerjoin], [options])

Пример

Давайте создадим модели статьи и пользователя со связью один-ко-многим:

from sqlalchemy import ForeignKey from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] articles: Mapped[list['Article']] = relationship(back_populates='user') 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')) user: Mapped['User'] = relationship(back_populates='articles')

Теперь загрузим статью вместе с ее пользователем одним запросом:

<+python+> from sqlalchemy import create_engine, select from sqlalchemy.orm import Session, joinedload from models import Base, User, Article engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: user = User(title='user') article = Article(title='article', user=user) session.add_all([user, article]) session.commit() stmt = select(Article).options(joinedload(Article.user)) res = session.scalars(stmt).all() print(res[0].title, '-', res[0].user.title) <-python+>

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

<+python+> "article - user" <-python+>

Пример

Давайте посмотрим, какой SQL-запрос генерирует joinedload:

<+python+> from sqlalchemy import create_engine, select from sqlalchemy.orm import Session, joinedload from models import Base, User, Article engine = create_engine('sqlite:///:memory:', echo=True) Base.metadata.create_all(engine) with Session(engine) as session: stmt = select(Article).options(joinedload(Article.user)) res = session.scalars(stmt).all() <-python+>

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

SELECT articles.id, articles.title, articles.user_id, users_1.id AS id_1, users_1.title AS title_1 FROM articles LEFT OUTER JOIN users AS users_1 ON users_1.id = articles.user_id

Пример

Давайте загрузим связанные коллекции пользователя вместе с его статьями:

<+python+> from sqlalchemy import create_engine, select from sqlalchemy.orm import Session, joinedload from models import Base, User, Article engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: user = User(title='user') user.articles = [Article(title='article 1'), Article(title='article 2')] session.add(user) session.commit() stmt = select(User).options(joinedload(User.articles)) res = session.scalars(stmt).unique().all() print([a.title for a in res[0].articles]) <-python+>

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

<+python+> ['article 1', 'article 2'] <-python+>

Обратите внимание на вызов метода unique. При загрузке коллекций через joinedload строки дублируются, поэтому SQLAlchemy требует явно применить дедупликацию.

Пример

Давайте используем параметр innerjoin, чтобы заменить LEFT OUTER JOIN на INNER JOIN:

<+python+> from sqlalchemy import create_engine, select from sqlalchemy.orm import Session, joinedload from models import Base, User, Article engine = create_engine('sqlite:///:memory:', echo=True) Base.metadata.create_all(engine) with Session(engine) as session: stmt = select(Article).options(joinedload(Article.user, innerjoin=True)) res = session.scalars(stmt).all() <-python+>

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

SELECT articles.id, articles.title, articles.user_id, users_1.id AS id_1, users_1.title AS title_1 FROM articles JOIN users AS users_1 ON users_1.id = articles.user_id

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

  • функцию selectinload,
    которая загружает связи отдельным SELECT запросом
  • функцию subqueryload,
    которая загружает связи через подзапрос
  • функцию contains_eager,
    которая использует уже готовый JOIN для загрузки
  • функцию lazyload,
    которая задает ленивую стратегию загрузки связи
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить