Ответ
Объекты QuerySet в Django являются "ленивыми" (lazy). Это означает, что сам по себе факт создания, фильтрации или объединения QuerySet не вызывает запроса к базе данных. Запрос выполняется только в тот момент, когда данные из QuerySet действительно необходимы.
Запрос к БД (оценка QuerySet) происходит в следующих случаях:
-
Итерация
- Перебор в цикле:
for item in MyModel.objects.all(): ... - Преобразование в список:
list(MyModel.objects.all())
- Перебор в цикле:
-
Получение одного объекта или среза
- Доступ по индексу:
MyModel.objects.all()[0] - Использование среза с шагом:
MyModel.objects.all()[::2] - Вызов методов, возвращающих один объект:
.get(),.first(),.last(),.latest(),.earliest()
- Доступ по индексу:
-
Подсчет и проверка существования
- Вызов
len():len(MyModel.objects.all()) - Вызов
bool()или проверка вif:if MyModel.objects.filter(...): ... - Явные вызовы:
.count(),.exists()
- Вызов
-
Агрегация
- Вызов методов
.aggregate()и.annotate().
- Вызов методов
Пример ленивого выполнения:
# 1. Создание QuerySet. Запроса к БД в этот момент НЕТ.
# Django просто конструирует SQL-запрос в памяти.
>>> active_users = User.objects.filter(is_active=True)
# 2. Подсчет. Здесь выполняется первый запрос к БД (SELECT COUNT(*)...).
>>> print(f"Total active users: {active_users.count()}")
# 3. Итерация. Здесь выполняется второй запрос к БД (SELECT * ...).
# Данные извлекаются и кешируются в QuerySet.
>>> for user in active_users:
... print(user.username)
# 4. Повторная итерация. Запроса к БД НЕТ, используются кешированные результаты.
>>> for user in active_users:
... print(user.email)
Понимание ленивости QuerySet критически важно для написания производительного кода в Django, так как позволяет избежать лишних обращений к базе данных.