← Назад к вопросам
Зачем нужен 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 запроса к БД
Как это работает
- Первый запрос: получаем все книги (
SELECT * FROM book) - Второй запрос: получаем всех авторов для этих книг (
SELECT * FROM author WHERE id IN (...)) — одним запросом - В памяти 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)
Важные нюансы
- Фильтрация после prefetch — старайся фильтровать ДО
prefetch_related() - Условный 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)
)
- Отладка — используй
django.db import connection; print(connection.queries)для подсчёта запросов
prefetch_related() — критически важный инструмент для оптимизации производительности Django приложений.