在使用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时,性能优化是很重要的。
在思考使用哪些功能时,可以参考这篇文章,选择最适合你应用程序的方式。
祝愿你的项目更加高效、快速地运行! 🔥

目前没有评论。