使用 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 被評估):
- 在
for
循環中遍歷時 - 調用
list(qs)
時 - 調用
bool(qs)
(if qs:
等條件語句中) - 調用
.count()
、.exists()
、.first()
、.last()
等方法時
📌 結論
✅ .only()
→ 保持模型對象 + 僅提前加載特定字段
🔹 可使用 ORM 功能 (.save()
, .delete()
)
🔹 但訪問未提前加載的字段時會發生額外查詢
✅ .values()
→ 返回字典列表 + 無額外查詢
🔹 由於不是模型對象,因此無法使用 .save()
、.delete()
🔹 查詢集本身保持不變,因此可以使用 .filter()
、.annotate()
🔹 外鍵字段默認僅返回 ID 值 → 必須使用 author__name
這樣的明確指定
💡 也就是說,若需保持模型對象,應使用 .only()
,單純數據查詢時則選擇 .values()
! 🚀
🎯 使用 Django ORM 時性能優化至關重要。
在考慮使用何種功能時,請參考此文,選擇最適合您的應用方式。
祝您的項目運行得更高效、更快速! 🔥
Add a New Comment