Ответ
Lazy loading (ленивая загрузка) — это механизм оптимизации в Django ORM, при котором запрос к базе данных не выполняется до тех пор, пока данные не понадобятся.
Это позволяет экономить ресурсы, не загружая избыточную информацию.
Как это работает на практике:
-
Ленивые QuerySet: Создание
QuerySetне вызывает запроса к БД. Запрос выполняется только при попытке получить данные (например, в цикле, при срезе или вызовеlist()).# На этом этапе SQL-запрос НЕ выполняется users = User.objects.filter(is_staff=True) # Запрос выполнится только здесь, при первой итерации for user in users: print(user.username) -
Связанные объекты (Relations): При получении объекта связанные с ним по
ForeignKeyилиManyToManyFieldобъекты не загружаются сразу.# 1-й запрос: получаем объект статьи article = Article.objects.get(id=1) # 2-й запрос: получаем связанного автора только при обращении к нему print(article.author.name)
Проблема N+1 и её решение
Неосознанное использование lazy loading часто приводит к проблеме N+1: один начальный запрос порождает N дополнительных запросов в цикле. Для её решения Django предлагает методы для "жадной" (eager) загрузки:
select_related(*fields): Загружает связанные объекты (один-к-одному, многие-к-одному) одним SQL-запросом с помощьюJOIN.prefetch_related(*fields): Загружает связанные объекты (многие-ко-многим, многие-к-одному) отдельными запросами и объединяет их на уровне Python. Эффективнее для множественных связей.
Пример решения:
# Плохо: 1 запрос за статьями + N запросов за авторами
articles = Article.objects.all()
for article in articles:
print(article.author.name) # Доп. запрос на каждой итерации
# Хорошо: 1 запрос, который сразу получает статьи и авторов
articles = Article.objects.select_related('author').all()
for article in articles:
print(article.author.name) # Нет дополнительных запросов