Ответ
select_related() — это метод QuerySet в Django для оптимизации производительности путем сокращения количества запросов к базе данных. Он "заранее" загружает связанные объекты по полям ForeignKey и OneToOneField.
Проблема (N+1 запрос):
Без оптимизации при переборе объектов и обращении к связанной модели Django выполняет один запрос для получения основного списка и по одному дополнительному запросу для каждого объекта в цикле.
# Модели: Book -> Author (ForeignKey)
# Выполнит 1 (для книг) + N (для каждого автора) запросов
books = Book.objects.all()
for book in books:
# На каждой итерации происходит отдельный запрос к БД для получения автора
print(book.author.name)
Решение (select_related):
Метод select_related использует SQL JOIN для получения данных из основной и связанной таблиц за один запрос.
# Выполнит 1 запрос с JOIN
books = Book.objects.select_related('author').all()
for book in books:
# Данные об авторе уже загружены и доступны без доп. запроса
print(book.author.name)
Ключевые моменты:
- Типы связей: Работает только для отношений "один-к-одному" (
OneToOneField) и "многие-к-одному" (ForeignKey). - Цепочки: Можно загружать связанные объекты через несколько уровней:
select_related('author__country'). - Альтернатива: Для связей "многие-ко-многим" (
ManyToManyField) и обратныхForeignKeyиспользуетсяprefetch_related, который выполняет отдельный запрос и "склеивает" данные в Python.