Ответ
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.