使用 Django ORM 時,為了性能優化,可以通過 .values().only() 方法僅獲取特定字段。
在之前的文章中,我詳細介紹了 Django QuerySet的 .values() 方法是什麼?,如果您尚未查看,建議您參考一下。 😊

要檢查上一篇文章,請點擊! 

Django QuerySet的 .values() 方法是什麼?

由於在撰寫關於 .values() 的文章時,發現 .only() 方法的工作方式與之相似但有所不同,因此我準備了這篇文章,以幫助更深入地理解 Django ORM。 🚀

1️⃣ .only().values() 的差異

  .only() .values()
返回形式 模型實例 (Model 物件) 字典列表 (dict list)
使用目的 保持模型對象 + 僅載入某些字段 僅獲取特定字段,返回字典列表形式的查詢集
ORM 功能保持情況 ✅ 保持 (.save(), .delete() 可用) ❗ 無法使用模型方法 (.save(), .delete() ❌)
額外的 Lazy Loading ❗ 訪問未提前加載的字段時會發生額外查詢 ✅ 無額外查詢

2️⃣ .only() 使用方法及特點

.only()在保持模型對象的同時,僅提前加載特定字段的方法。但如果訪問未提前指定的字段,則會導致lazy loading,從而執行額外的查詢。

from myapp.models import Post

# 僅加載 title 和 author 字段的 QuerySet
qs = Post.objects.only("title", "author")

# 輸出檢查 (QuerySet 本身是延遲評估的)
print(qs)  # SQL 不會執行

# 字段訪問
for post in qs:  # ✅ 此時 SQL 被執行
    print(post.title)  # ✅ 預先加載的字段 (無額外查詢)
    print(post.body)   # 🚨 未預先加載的字段 → 會發生額外查詢

🔹 注意事項:
.only()立即加載指定的字段,其他字段在需要時將發送額外查詢
因此,為了防止不必要的查詢,建議.only() 中指定所有需要的字段。

3️⃣ .values() 使用方法及特點

.values() 是僅返回特定字段並以字典列表形式返回的。由於返回的不是模型對象,因此無法使用 ORM 功能。
但查詢集本身保持不變,因此仍然可以使用 .filter().annotate() 等方法。

# 僅獲取 title 和 author 字段,但返回字典形式的結果
qs = Post.objects.values("title", "author")

# 查詢集本身是延遲評估的 (SQL 不會執行)
print(qs)

# 使用字典數據 (此時 SQL 被執行)
for post in qs:
    print(post["title"])  # ✅ 無額外查詢

🔹 注意事項:
使用 .values() 時,外鍵字段默認僅返回 ID 值
因此,如果需要關聯模型的特定字段值,需要明確指定,例如 "author__name"

# 獲取外鍵字段的特定值
qs = Post.objects.values("title", "author__name")

for post in qs:
    print(post["author__name"])  # ✅ 獲取 author 對象的 name 字段

以上示例代碼指定了外鍵關聯的 "author__name" 字段,因此預期的 author.name 將輸出,但如果僅指定了 "author",則將僅輸出 author 對象的 ID 編號。

4️⃣ .only().values() 何時使用?

使用目的 .only() 推薦 .values() 推薦
必須保持模型對象的情況
需要使用 ORM 功能 (.save(), .delete(), .update())
性能優化 (防止不必要的字段加載)
防止額外的 Lazy Loading ❌ (可能有額外查詢) ✅ (無額外查詢)

5️⃣ .values() 也會延遲評估!

雖然 .values() 看起來像是會立即評估,但其實 Django 的查詢集默認是全部都是延遲評估 (Lazy Evaluation) 方法
也就是說,調用 .values() 時,SQL 並不會立即執行,而是在實際使用數據時進行評估。 🚀

.values() 也會延遲評估 (SQL 不會立即執行)

qs = Post.objects.values("title", "author")  # ❌ SQL 並不會被執行
print(qs)  # ❌ 僅顯示 QuerySet 對象的資訊 (SQL 未執行)

for post in qs:  # ✅ 此時 SQL 被執行
    print(post["title"])

✅ 什麼時候查詢集會被評估?

包含 .values() 的查詢集會在以下情況下立即執行 (SQL 被評估)

  1. for 循環中遍歷時
  2. 調用 list(qs)
  3. 調用 bool(qs) (if qs: 等條件語句中)
  4. 調用 .count().exists().first().last() 等方法時

📌 結論

.only()保持模型對象 + 僅提前加載特定字段
     🔹 可使用 ORM 功能 (.save(), .delete())
     🔹 但訪問未提前加載的字段時會發生額外查詢

.values()返回字典列表 + 無額外查詢
     🔹 由於不是模型對象,因此無法使用 .save().delete()
     🔹 查詢集本身保持不變,因此可以使用 .filter().annotate()
     🔹 外鍵字段默認僅返回 ID 值 → 必須使用 author__name 這樣的明確指定

💡 也就是說,若需保持模型對象,應使用 .only(),單純數據查詢時則選擇 .values() 🚀

🎯 使用 Django ORM 時性能優化至關重要。

在考慮使用何種功能時,請參考此文,選擇最適合您的應用方式
祝您的項目運行得更高效、更快速! 🔥

Django QuerySet .only() vs .values() flowchart