在使用Django開發的過程中,您會經常遇到'延遲評估(Lazy Evaluation)'這個術語。
不過,很多人可能對這個概念的具體含義以及它在Django中的運作方式好奇。
在本文中,我們將探討'延遲評估'的含義以及如何在Django ORM中應用它

1️⃣ 延遲評估(Lazy Evaluation)是什麼?

「在需要之前不從資料庫中獲取數據!」

Django的QuerySet基本上遵循延遲評估(Lazy Evaluation)
也就是說,即使創建了QuerySet,除了實際請求數據之前,查詢不會被執行。

示例:延遲評估

from myapp.models import Post

# 創建QuerySet(尚未從資料庫中獲取數據)
post_list = Post.objects.filter(status='PB')  

print(post_list)  
# <QuerySet [ ]># ✅ 尚未執行查詢

# 🔥 當實際請求數據時查詢被執行
for post in post_list:
    print(post.title)  # 🚀 此時會發生DB查詢
  • post_list是QuerySet對象,但尚未訪問資料庫
  • 但是在使用數據時,查詢才會被執行

這就是「延遲評估」(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())。 ✅ 但由於提前獲取了數據,所以之後可以快速使用而無需訪問資料庫。

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造成負擔,無法進行額外的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