在使用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() ❌) |
附加的懒加载 | ❗ 当访问未提前加载的字段时,会产生额外的查询 | ✅ 没有额外查询 |
2️⃣ .only()
的使用方法及特点
.only()
是一种保持模型对象同时提前加载特定字段的方法。但如果访问未提前指定的字段,将会发生懒加载,可能会执行额外的查询。
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功能。
但是,QuerySet 本身得以保持,因此仍可使用 .filter()
、.annotate()
等方法。
# 仅获取 title 和 author 字段,结果以字典形式返回
qs = Post.objects.values("title", "author")
# QuerySet 本身是延迟评估的 (SQL 不会执行)
print(qs)
# 利用字典数据 (此时执行 SQL)
for post in qs:
print(post["title"]) # ✅ 没有额外查询
🔹 注意事项:
使用 .values()
时,ForeignKey 字段默认只返回 ID 值。
所以如果需要关系模型的特定字段值,必须明确指定,例如 "author__name"
。
# 获取 ForeignKey 字段的特定值
qs = Post.objects.values("title", "author__name")
for post in qs:
print(post["author__name"]) # ✅ 获取 author 对象的 name 字段
上述示例代码中,由于指定了通过 ForeignKey 连接的 "author__name"
字段,因此结果将输出预期的 author.name,但如果指定为 "author"
,则只会简单输出 author 对象的 id 号。
4️⃣ .only()
vs .values()
何时使用?
使用目的 | .only() 推荐 |
.values() 推荐 |
---|---|---|
需要保持模型对象的情况 | ✅ | ❌ |
需要使用ORM功能 (.save() , .delete() , .update() ) |
✅ | ❌ |
性能优化 (避免不必要的字段加载) | ✅ | ✅ |
防止额外的懒加载 | ❌ (可能导致额外查询) | ✅ (没有额外查询) |
5️⃣ .values()
也是延迟评估!
.values()
看起来可能是立即评估的,但实际上Django的QuerySet本质上是全部延迟评估 (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"])
✅ 何时评估 QuerySet?
包含 .values()
的 QuerySet 在以下情况会立即执行(SQL 会评估):
- 在
for
循环中遍历时 - 调用
list(qs)
时 - 调用
bool(qs)
(如条件语句中的if qs:
)时 - 调用
.count()
,.exists()
,.first()
,.last()
等方法时
📌 结论
✅ .only()
→ 保持模型对象 + 提前加载特定字段
🔹 可使用 ORM 功能 (.save()
, .delete()
)
🔹 但访问未提前加载的字段时会产生额外查询
✅ .values()
→ 返回字典列表 + 没有额外查询
🔹 由于不是模型对象,因此无法使用 .save()
, .delete()
🔹 QuerySet 本身得以保持,因此可以使用 .filter()
, .annotate()
🔹 ForeignKey 字段默认只返回 ID 值 → 必须指定为 author__name
💡 也就是说,如果需要保持模型对象,请选择 .only()
,简单查询数据时选择 .values()
! 🚀
🎯 使用Django ORM时,性能优化是很重要的。
在思考使用哪些功能时,可以参考这篇文章,选择最适合你应用程序的方式。
祝愿你的项目更加高效、快速地运行! 🔥
댓글이 없습니다.