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クエリを防げますが、時には即時評価がより適切な場合もあります!
Add a New Comment