При разработке на Django вы часто сталкиваетесь с термином 'ленивая оценка (Lazy Evaluation)'.
Но многие могли не понимать, что именно означает этот концепт и как он работает в Django.
В этой статье мы рассмотрим 'что такое ленивая оценка и как она используется в Django ORM'.

1️⃣ Что такое ленивая оценка (Lazy Evaluation)?

"Данные из базы данных не извлекаются, пока они не понадобятся!"

QuerySet в Django в основном следует ленивой оценке (Lazy Evaluation).
То есть, даже если вы создадите QuerySet, запрос не выполняется до тех пор, пока фактически не будет запрошен набор данных.

Пример: Ленивая оценка

from myapp.models import Post

# Создание QuerySet (данные из DB еще не извлечены)
post_list = Post.objects.filter(status='PB')  

print(post_list)  
# <QuerySet [ ]># ✅ Запрос к DB еще не выполнен

# 🔥 Запрос к DB выполняется при фактическом извлечении данных
for post in post_list:
    print(post.title)  # 🚀 Запрос к DB происходит здесь
  • post_list — это объект QuerySet, но он еще не обращается к БД
  • Тем не менее, при использовании данных запрос фактически выполняется

Это и есть "ленивая оценка"! 

2️⃣ Что такое немедленная оценка (Eager Evaluation)?

"Данные извлекаются немедленно и преобразуются в список или переменную!"

Чтобы прервать ленивую оценку и немедленно выполнить QuerySet, можно использовать немедленную оценку (Eager Evaluation).

Пример: Немедленная оценка

post_list = list(Post.objects.filter(status='PB'))  # ✅ Немедленно выполняется запрос к БД

print(post_list)  
# [<Post: Post 1>, <Post: Post 2>] # 🚀 Возвращается не QuerySet, а фактический список объектов!

📌 Применив немедленную оценку:

  • QuerySet преобразуется в список и данные извлекаются немедленно
  • Больше нельзя использовать функции Django ORM (.filter(), .annotate())

3️⃣ Немедленная оценка для `.values()` и `.values_list()`

.values() и .values_list() также в основном сохраняют ленивую оценку, но если обернуть их в list(), то применяется немедленная оценка.

✅ Сохранение ленивой оценки (Lazy Evaluation)

post_list = Post.objects.filter(status='PB').values("id", "title")

print(post_list)  
# <QuerySet [{'id': 1, 'title': 'First Post'}, {'id': 2, 'title': 'Second Post'}]>  # Объект QuerySet

🚨 В этом состоянии это все еще QuerySet, поэтому он оценивается каждый раз при использовании данных. 🔥 Применение немедленной оценки

post_list = list(Post.objects.filter(status='PB').values("id", "title"))

print(post_list)  
# [{'id': 1, 'title': 'First Post'}, {'id': 2, 'title': 'Second Post'}]  # 🚀 Применена немедленная оценка (преобразовано в список)

✅ Теперь это список, а не QuerySet, и больше нельзя использовать функции Django ORM (.filter(), .annotate()). ✅ Но данные были извлечены заранее, что позволяет быстро использовать их без доступа к БД.

4️⃣ `.count()` и `.exists()` в QuerySet выполняются немедленно!

QuerySet в Django в основном ленивый, но некоторые методы автоматически выполняют немедленную оценку.

.count() (немедленный запрос)

post_count = Post.objects.filter(status='PB').count()
# ✅ Немедленный запрос выполняется (SELECT COUNT(*) FROM post WHERE status='PB';)

.exists() (немедленный запрос)

has_published_posts = Post.objects.filter(status='PB').exists()
# ✅ Немедленный запрос выполняется (SELECT 1 FROM post WHERE status='PB' LIMIT 1;)

.count() и .exists() выполняются немедленно, даже если QuerySet не преобразуется.

5️⃣ Сравнительная таблица: Ленивая оценка и Немедленная оценка

  Ленивая оценка (Lazy Evaluation) Немедленная оценка (Eager Evaluation)
Описание Запросы не выполняются до тех пор, пока это не потребуется Запросы выполняются немедленно и данные извлекаются
Примеры Состояние QuerySet сохраняется list(QuerySet), .values_list(), .count()
Преимущества Избежание ненужных запросов к БД, экономия памяти Быстрый доступ к данным после запроса к БД
Недостатки Запрос может выполняться каждый раз, когда он нужен Нагрузка на БД происходит немедленно, дополнительные операции ORM невозможны
Примеры использования .filter(), .annotate(), .order_by() list(), .count(), .exists(), .values()

 Применяя немедленную оценку (list(QuerySet)), данные загружаются немедленно, и дополнительные запросы к БД можно избежать!

 Но функции QuerySet больше не доступны, поэтому нужно тщательно решать, когда применять это! 

 

📌 Заключение

✅ QuerySet в Django в основном следует ленивой оценке (Lazy Evaluation).
✅ Используя немедленную оценку (Eager Evaluation), данные извлекаются немедленно из БД, и QuerySet преобразуется в список.
✅ Обернув .values(), .values_list() в list(), происходит немедленная оценка.
Сохраняя ленивую оценку, можно предотвратить ненужные запросы к БД, но иногда немедленная оценка может быть более уместной! 

 

Django QuerySet Lazy vs Eager Evaluation