在使用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 会评估)

  1. for 循环中遍历时
  2. 调用 list(qs)
  3. 调用 bool(qs) (如条件语句中的 if qs:)时
  4. 调用 .count(), .exists(), .first(), .last() 等方法时

📌 结论

.only()保持模型对象 + 提前加载特定字段
     🔹 可使用 ORM 功能 (.save(), .delete())
     🔹 但访问未提前加载的字段时会产生额外查询

.values()返回字典列表 + 没有额外查询
     🔹 由于不是模型对象,因此无法使用 .save(), .delete()
     🔹 QuerySet 本身得以保持,因此可以使用 .filter(), .annotate()
     🔹 ForeignKey 字段默认只返回 ID 值 → 必须指定为 author__name

💡 也就是说,如果需要保持模型对象,请选择 .only(),简单查询数据时选择 .values() 🚀

🎯 使用Django ORM时,性能优化是很重要的。

在思考使用哪些功能时,可以参考这篇文章,选择最适合你应用程序的方式
祝愿你的项目更加高效、快速地运行! 🔥

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