← Назад к вопросам

Зачем нужен prefetch_related в Django?

1.8 Middle🔥 221 комментариев
#Django#Базы данных (SQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

prefetch_related в Django

prefetch_related() — это метод оптимизации запросов в Django ORM, который решает проблему N+1 запросов за счёт выполнения дополнительных запросов к БД в Python памяти.

Проблема N+1

Рассмотрим типичную ситуацию:

# Модели
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

# БЕЗ оптимизации — N+1 проблема
books = Book.objects.all()  # 1 запрос
for book in books:  # Допустим, 100 книг
    print(book.author.name)  # 100 дополнительных запросов!
# Итого: 101 запрос к БД

Решение с prefetch_related

# С prefetch_related — 2 запроса
books = Book.objects.prefetch_related(author)
for book in books:
    print(book.author.name)  # Данные уже в памяти
# Итого: 2 запроса к БД

Как это работает

  1. Первый запрос: получаем все книги (SELECT * FROM book)
  2. Второй запрос: получаем всех авторов для этих книг (SELECT * FROM author WHERE id IN (...)) — одним запросом
  3. В памяти Python: Django связывает объекты Author с объектами Book

Отличие от select_related

select_related() использует SQL JOIN — для один-к-одному и внешних ключей:

# select_related использует JOIN
books = Book.objects.select_related(author)
# SELECT book.*, author.* FROM book JOIN author ON book.author_id = author.id

prefetch_related() использует отдельные запросы — для обратных связей и many-to-many:

# Обратная связь (один автор → много книг)
authors = Author.objects.prefetch_related(book_set)

# Many-to-many
class Tag(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    tags = models.ManyToManyField(Tag)

books = Book.objects.prefetch_related(tags)  # prefetch_related!

Практический пример с вложенными отношениями

# Сложный случай
authors = Author.objects.prefetch_related(
    book_set__tags,  # Книги автора и их теги
    book_set__comments  # Комментарии к книгам
)

for author in authors:
    for book in author.book_set.all():
        for tag in book.tags.all():
            print(tag.name)  # Всё уже в памяти

Когда использовать

  • prefetch_related: many-to-many, обратные связи (ForeignKey), вложенные отношения
  • select_related: ForeignKey, OneToOneField (когда гарантирован один объект)
  • Комбинируй: Book.objects.select_related(author).prefetch_related(tags)

Важные нюансы

  1. Фильтрация после prefetch — старайся фильтровать ДО prefetch_related()
  2. Условный prefetch — используй Prefetch() объект для сложной логики:
from django.db.models import Prefetch

recent_books = Book.objects.filter(created_at__gte=date)
authors = Author.objects.prefetch_related(
    Prefetch(book_set, queryset=recent_books)
)
  1. Отладка — используй django.db import connection; print(connection.queries) для подсчёта запросов

prefetch_related() — критически важный инструмент для оптимизации производительности Django приложений.

Зачем нужен prefetch_related в Django? | PrepBro