Djangoで開発をしていると、'遅延評価(Lazy Evaluation)'という用語をよく目にします。
ですが、この概念が正確に何であるか、Djangoでどのように動作するのか気になっていた方も多いでしょう。
今回の記事では、'遅延評価'とは何か、Django ORMでどのように活用されるのかについて見ていきましょう。

1️⃣ 遅延評価(Lazy Evaluation)とは?

"必要になるまでDBからデータを取得しない!"

DjangoのQuerySetは基本的に遅延評価(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オブジェクトですが、まだDBにアクセスしていない
  • しかしデータを使用するとき 実際にクエリが実行される

これが「遅延評価」(Lazy Evaluation)です! 

2️⃣ 即時評価(Eager Evaluation)とは?

"データを即座に取得してリストや変数に変換する!"

遅延評価を破ってQuerySetを即座に実行するには、即時評価(Eager Evaluation)を使用すれば良いのです。

例: 即時評価

post_list = list(Post.objects.filter(status='PB'))  # ✅ 即座にDBクエリが実行される

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())を利用できません。 ✅ しかしデータを事前に取得したので, その後DBアクセスなしで迅速に活用可能です。

4️⃣ QuerySetにおける.count().exists()は即時評価される!

DjangoのQuerySetは基本的に遅延評価ですが、一部のメソッドは自動的に即時評価を実行します。

.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()
利点 不要なDBクエリを防ぎ、メモリを節約する DB照会後、素早くデータを活用できる
欠点 必要なときにクエリが実行される可能性がある DB負担が即座に発生し、追加のORM操作ができない
使用例 .filter(), .annotate(), .order_by() list(), .count(), .exists(), .values()

 即時評価 (list(QuerySet))を適用するとデータが即座に読み込まれ, 追加のDBクエリを防ぐことができます!

 ですがQuerySet機能をもはや使用できないため, いつ適用するか慎重に決める必要があります! 

 

📌 結論

✅ DjangoのQuerySetは基本的に遅延評価(Lazy Evaluation)に従います。
✅ 即時評価(Eager Evaluation)を使用するとDBからデータを即座に取得し、QuerySetがリストに変換される
.values(), .values_list()list()でラップすると即時評価される。
遅延評価を維持すれば不要なDBクエリを防げますが、時には即時評価がより適切な場合もあります! 

 

Django QuerySet Lazy vs Eager Evaluation