Ответ
prefetch_related — это метод менеджера моделей Django, предназначенный для оптимизации запросов к базе данных путем сокращения их количества при доступе к связанным объектам через отношения many-to-many или обратные foreign key.
Он решает проблему "N+1 запросов", когда для получения связанных данных для N объектов выполняется N дополнительных запросов.
Как это работает:
prefetch_related выполняет отдельный запрос для связанных объектов и "соединяет" данные на уровне Python, а не на уровне базы данных с помощью JOIN.
Пример:
# models.py
class Topping(models.Model):
name = models.CharField(max_length=30)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
Плохой подход (N+1 проблема):
# Выполняется 1 запрос для всех пицц
pizzas = Pizza.objects.all()
# Для каждой пиццы выполняется отдельный запрос к топпингам
for pizza in pizzas:
print(pizza.toppings.all()) # +N запросов
Оптимизированный подход с prefetch_related:
# Выполняется всего 2 запроса: один для пицц, второй для всех связанных топпингов
pizzas = Pizza.objects.prefetch_related('toppings')
for pizza in pizzas:
# Данные уже загружены, дополнительный запрос не выполняется
print(pizza.toppings.all())
Отличие от select_related
| Критерий | select_related |
prefetch_related |
|---|---|---|
| Тип SQL-запроса | Выполняет один сложный SQL-запрос с JOIN. |
Выполняет несколько запросов (минимум два) и соединяет данные в Python. |
| Тип отношений | ForeignKey, OneToOneField (один-ко-многим, один-к-одному). |
ManyToManyField, обратные ForeignKey (многие-ко-многим, многие-к-одному). |
| Когда использовать | Когда вы работаете с объектом, на который указывает связь (прямая связь). | Когда вы работаете с набором связанных объектов. |