Для чего в Django используется prefetch_related и в чем его отличие от select_related?

Ответ

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 (многие-ко-многим, многие-к-одному).
Когда использовать Когда вы работаете с объектом, на который указывает связь (прямая связь). Когда вы работаете с набором связанных объектов.