Функция 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')
Теперь загрузим статью вместе с ее пользователем одним запросом:
Результат выполнения кода:
Пример
Давайте посмотрим, какой SQL-запрос
генерирует joinedload:
Итоговый 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
Пример
Давайте загрузим связанные коллекции пользователя вместе с его статьями:
Результат выполнения кода:
Обратите внимание на вызов метода
unique. При загрузке коллекций через
joinedload строки дублируются,
поэтому SQLAlchemy требует явно
применить дедупликацию.
Пример
Давайте используем параметр innerjoin,
чтобы заменить LEFT OUTER JOIN на
INNER JOIN:
Итоговый 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,
которая задает ленивую стратегию загрузки связи