When using Django ORM, there are methods like .values()
and .only()
that allow you to fetch only specific fields for performance optimization.
In my previous post, I covered What is the .values()
method of Django QuerySet? in detail, and if you haven't checked it out yet, I highly recommend you take a look. 😊
To check the previous article, click!
What is the .values()
method of Django QuerySet?
While writing about .values()
, I thought it would be helpful to explain the .only()
method, which works in a similar yet different way, to deepen your understanding of Django ORM. That’s why I prepared this article. 🚀
1️⃣ Differences between .only()
and .values()
.only() |
.values() |
|
---|---|---|
Return Type | Model Instance (Model object) | List of Dictionaries (dict list) |
Usage Purpose | Keep model object + load only some fields | Return a queryset with specific fields in the form of a list of dictionaries |
Maintain ORM Functionality | ✅ Maintained (.save() , .delete() available) |
❗ Model methods unavailable (.save() , .delete() ❌) |
Additional Lazy Loading | ❗ Additional query occurs when accessing fields not preloaded | ✅ No additional queries |
2️⃣ How to use .only()
and its features
.only()
is a method that allows you to keep the model object while preloading specific fields. However, if you access fields that were not specified in advance, Lazy Loading occurs, causing additional queries to be executed.
from myapp.models import Post
# Loading only the title and author fields QuerySet
qs = Post.objects.only("title", "author")
# Check output (QuerySet itself is lazily evaluated)
print(qs) # SQL not executed
# Field access
for post in qs: # ✅ SQL executed at this time
print(post.title) # ✅ Preloaded field (no additional query)
print(post.body) # 🚨 Not preloaded field → additional query occurs
🔹 Note:
.only()
immediately loads only the specified fields, and executes additional queries for remaining fields as needed, so to avoid unnecessary queries, it’s recommended to specify all fields you need in .only()
.
3️⃣ How to use .values()
and its features
.values()
fetches specific fields and returns them in the form of a list of dictionaries. Since it returns dictionaries rather than model objects, ORM functionalities cannot be used.
However, the QuerySet itself is maintained, so methods like .filter()
and .annotate()
can still be used.
# Fetching only title and author fields, returning results in dictionary form
qs = Post.objects.values("title", "author")
# QuerySet itself is lazily evaluated (SQL not executed)
print(qs)
# Utilizing dictionary data (SQL executed at this point)
for post in qs:
print(post["title"]) # ✅ No additional queries
🔹 Note:
When you use .values()
, ForeignKey fields only return ID values by default.
Therefore, if you need specific field values from the related model, you must explicitly specify them like "author__name"
.
# Fetching specific values of ForeignKey fields
qs = Post.objects.values("title", "author__name")
for post in qs:
print(post["author__name"]) # ✅ Fetching name field from author object
In the above example, since we specified the "author__name"
field connected via ForeignKey, the intended author.name will be printed in the result. However, if it were specified as "author"
, only the ID number of the author object would be printed.
4️⃣ When to use .only()
vs .values()
?
Usage Purpose | .only() recommended |
.values() recommended |
---|---|---|
When you need to maintain the model object | ✅ | ❌ |
Need to use ORM functionalities (.save() , .delete() , .update() ) |
✅ | ❌ |
Performance optimization (to prevent unnecessary field loading) | ✅ | ✅ |
Avoiding additional Lazy Loading | ❌ (additional queries possible) | ✅ (no additional queries) |
5️⃣ .values()
also lazy evaluates!
While .values()
may seem to be executed immediately, in reality, Django’s QuerySet is fundamentally designed for all lazy evaluation.
In other words, executing SQL doesn’t happen the moment you call .values()
, but rather when the actual data is needed. 🚀
✅ .values()
also exhibits lazy evaluation (SQL not executed immediately)
qs = Post.objects.values("title", "author") # ❌ SQL not executed
print(qs) # ❌ Only QuerySet object info is displayed (SQL not executed)
for post in qs: # ✅ SQL executed at this point
print(post["title"])
✅ When is the QuerySet evaluated?
QuerySets, including .values()
, are executed immediately (SQL evaluated) in the following cases:
- When iterating in a
for
loop - When calling
list(qs)
- When calling
bool(qs)
(in conditions likeif qs:
) - When calling methods like
.count()
,.exists()
,.first()
,.last()
📌 Conclusion
✅ .only()
→ Maintain model object + preload specific fields
🔹 ORM functionality (.save()
, .delete()
) is available
🔹 But additional queries occur when accessing fields not preloaded
✅ .values()
→ Returns a list of dictionaries + no additional queries
🔹 Cannot use .save()
, .delete()
as it is not a model object
🔹 QuerySet itself is maintained, so .filter()
and .annotate()
can still be used
🔹 ForeignKey fields return only ID values by default → should be specified like author__name
💡 In summary, if you need to maintain model objects, choose .only()
; for simple data retrieval, opt for .values()
! 🚀
🎯 Performance optimization is crucial when using Django ORM.
When deciding which feature to use, refer to this article to select the optimal approach for your application!
I wish your projects run more efficiently and faster! 🔥
Add a New Comment