Как избавиться от N+1 запросов в Django ORM

Загрузите книги через Book.objects.select_related('author'). Тогда имя автора берётся из того же SQL-результата, и цикл не выполняет отдельный запрос для каждой книги.

Короткий ответ

Что ответить на собеседовании

Загрузите книги через Book.objects.select_related('author'). Тогда имя автора берётся из того же SQL-результата, и цикл не выполняет отдельный запрос для каждой книги.

Подробный разбор

Ответ с пояснениями

Условие

Требуется повысить эффективность запросов к базе, избегая лишних обращений к связанным моделям. В примере ниже показана простая схема с моделями Author и Book. Необходимо изменить логику так, чтобы при выводе имени автора книги не происходило отдельного запроса для каждой записи.


from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=255)

class Book(models.Model):
    name = models.CharField(max_length=255)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
    price = models.IntegerField(default=100)


all_books = Book.objects.all()

# Фильтрация книг по авторам
author_1_books = all_books.filter(author_id=1)
author_2_books = all_books.filter(author_id=2)


for book in all_books:
    print(book.author.name)

Ответ

Загрузите книги через Book.objects.select_related('author'). Тогда имя автора берётся из того же SQL-результата, и цикл не выполняет отдельный запрос для каждой книги.

Исправление для ForeignKey:

all_books = Book.objects.select_related('author').all()
for book in all_books:
    print(book.author.name)

Обычно это один SELECT с JOIN вместо одного SELECT книг и N загрузок авторов. Два filter из исходного примера, пока они не вычислены, вообще не создают SQL. Для обратных и many-to-many связей применяют prefetch_related, который загружает связанные записи отдельным запросом и объединяет их в Python.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее