Ответ
select_related()
— это метод Django ORM для оптимизации производительности, который решает проблему "N+1 запросов". Он "жадно" загружает связанные объекты через FOREIGN KEY
или OneToOne
в одном SQL-запросе с помощью JOIN
.
Это позволяет избежать дополнительных обращений к базе данных при доступе к связанным моделям в цикле.
Проблема: N+1 запросов
Без select_related()
для каждой книги будет выполнен отдельный SQL-запрос для получения автора.
# models.py
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# views.py
# Выполняется 1 запрос для получения всех книг
books = Book.objects.all()
# В цикле для каждой из N книг выполняется еще 1 запрос к автору
for book in books:
print(f'"{book.title}" от {book.author.name}') # <-- Здесь происходит N доп. запросов
Решение: select_related()
Все данные о книгах и их авторах загружаются за один SQL-запрос.
# Выполняется 1 запрос, который объединяет таблицы Book и Author
books = Book.objects.select_related('author').all()
# Дополнительных запросов к БД нет, данные уже загружены
for book in books:
print(f'"{book.title}" от {book.author.name}')
Важные моменты:
- Типы связей: Работает только для
ForeignKey
иOneToOne
. - Направление: Следует по "прямым" связям (не по обратным).
- Альтернатива: Для связей
ManyToManyField
и обратныхForeignKey
используетсяprefetch_related()
, который выполняет отдельный запрос и "соединяет" данные в Python.