Django: Top 40 Useful QuerySets
✨ Django’s ORM is super powerful, and the real magic lies in its QuerySet methods. Whether you’re building a simple blog or a complex e-commerce system, knowing how to use these QuerySets effectively can save you a ton of time.
Here are 40 Django QuerySet methods that I find incredibly useful — explained simply and with examples.
# 🔹 Top 40 Useful Django QuerySet Methods
# 📦 Basic & Everyday Use
1. all()
2. filter()
3. exclude()
4. get()
5. order_by()
6. values()
7. values_list()
8. annotate()
9. aggregate()
10. distinct()
11. exists()
12. select_related()
13. prefetch_related()
14. update()
15. delete()
16. create()
17. bulk_create()
18. in_bulk()
19. select_for_update()
20. defer() / only()
# 🛠 Query Logic & Filtering
21. reverse()
22. earliest() / latest()
23. first() / last()
24. count()
25. get_or_create()
26. update_or_create()
27. raw()
28. iterator()
29. union() / intersection() / difference()
30. db_manager()
# 🔍 Advanced & Custom Logic
31. Q()
32. F()
33. Case / When
34. from_queryset() # สร้าง custom manager
35. Subquery() / OuterRef()
36. Exists()
37. as_manager()
38. select_for_update(nowait=True) / skip_locked=True
39. select_for_update(of=...)
40. none()Extra notes:
If you want to cut query times like a Genius please considerate in using.
- select_related()
Reduce N+1 queries
For related object (foreign key,one-to-one). - prefetch_related()
ForMany-to-ManyandReverse Foreign key. - annotate()
Use query in SQL level likeCount(). - only() เอา, defer() ไม่เอา
To reduce all fields in model from default.Smaller queries > less memory > faster network > better DB caching. - exists()
When just need to check have or have no.
And finally remember to use tool: django-debug-toolbar to check result.
1. all()
Returns all objects in the table.
Product.objects.all() # อันนี้ใช่บ่อยจนไม่น่ามาเขียนล่ะนะ 552. filter()
Filter objects based on conditions.
Product.objects.filter(price__gt=100)3. exclude()
Exclude specific objects from the result.
Product.objects.exclude(category="Clothing")4. get()
Get exactly one object. Raises error if none or more than one found.
Product.objects.get(id=1) # อันนี้ต้องระวังนะ ถ้า get ไม่เจอจะพังได้ ได้ object กลับมาเลย5. order_by()
Sort the results.
Product.objects.order_by('-price') # Descending6. values()
Returns dictionaries instead of model instances.
# ได้กลับมาเป็น list<dict> นะ เฉพาะ field ที่เราต้องการเท่านั้น
Product.objects.values('name', 'price') # <QuerySet [{'name': 'Q', 'price': '500'}]>7. values_list()
Like values() but returns tuples.
Product.objects.values_list('name', flat=True) # <QuerySet ['Q', 'Ji']>
# ถ้้าอยากได้ list ก็เอา list() ครอบได้เลยนะ8. annotate()
Add calculated fields.
from django.db.models import Count
Category.objects.annotate(product_count=Count('product'))
# สร้าง field ชื่อ "product_count" เพื่อใช้ในการ Count() นะ
# การทำแบบนี้จะเป็นการใช้ SQL level ในการ count ช่วยลดการ hit db or N+1
# ถ้าเทียบกับการ count แบบนี้จะช้ามากๆ- Used case we can use to reduce query time spending.
# Basic way to count objects.
# Fetch all related objects and use len() which is take times.
len(author.books.all())
# Better way.
# Count() will fetech at SQL level (no fetching full objects, just to count them).
# Count() no fetching full objects just to count them.
from django.db.models import Count
authors = Author.objects.annotate(book_count=Count('books'))
for author in authors:
print(author.book_count)9. aggregate()
Return summary values (not per object).
from django.db.models import Sum
Product.objects.aggregate(Sum('price'))
# จะได้ Summary ของ all fields "price" นะ10. distinct()
Remove duplicates.
Product.objects.values('category').distinct()11. exists()
Check if any record exists.
Product.objects.filter(price__lt=100).exists() # มียาง ตัวเทอ- ถ้าแค่ต้องการเช็คว่ามีหรือไม่มี เราจะไม่ใช้แบบนี้นะ
# Inefficient way
if Product.objects.filter(price__lt=100).first():
# do something.
# Efficient way because will not fetch object itself.
# It will generate only 1 query instead of pulling full rows.
if Product.objects.filter(price__lt=100).exists():
# do something.12. select_related()
Optimize DB query by joining related object (foreign key, one-to-one).
Order.objects.select_related('customer')Another example if we don’t use select_relate() will cause issue N+1 like:
# The problem when not use select_related()
# 1 query for authors
authors = Author.objects.all()
# N queries for books
for author in authors:
books = author.books.all() # extra query every time
# The solution:
# It will help to join table in SQL level.
authors = Author.objects.select_related('profile').all()13. prefetch_related()
Optimize DB query for many-to-many or reverse foreign key.
Product.objects.prefetch_related('tags')14. update()
Bulk update.
Product.objects.filter(price__lt=100).update(price=100)
# เป็นการ update "price=100" ให้กับทุก rows ที่ได้จาก filter ด้านหน้านะ15. delete()
Delete objects.
Product.objects.filter(is_expired=True).delete()16. create()
Create and save an object.
Product.objects.create(name="Hat", price=250)17. bulk_create()
Create multiple objects at once.
Product.objects.bulk_create([
Product(name="Pen", price=30),
Product(name="Notebook", price=100),
])18. in_bulk()
Returns a dictionary of objects keyed by their IDs.
- เป็นการดึงข้อมูลหลายรายการในครั้งเดียวนะ และ return as dictionary.
- ใน
in_bulk()จะรับแค่ list of id เท่านั้นนะ by default. - ถ้า id ที่ใส่ไปไม่มีใน db ก็ไม่พังนะ แค่ไม่พ่น reponse นั้นๆกลับมา
User.objects.in_bulk([1, 2, 3])
# {2: <User: system>, 3: <User: support>, 1: <User: admin>}
# key = id, value = object นั้นๆ19. select_for_update() ✅ : Row-Level Locking
Locks rows until the end of transaction — useful in concurrent-safe updates like stock or balance.
Get Grassroot Engineer’s stories in your inbox
Join Medium for free to get updates from this writer.
พูดง่ายๆมันจะล๊อคเฉพาะแถวข้อมูล (row) ที่ตรงกับเงื่อนไขใน query โดยที่ไม่ได้ล็อกทั้งตารางนะ
- เป็นการ lock row in db ไว้ เพื่อป้องกันการแก้ไขข้อมูลซ้ำซ้อนในกรณีที่มีหลาย transactions เข้าถึงข้อมูลพร้อมกัน (concurrent access) จนกว่าจะจบ
transaction.atomic() - เพื่อป้องกัน race condition.
- ใช้ใน business logic ที่ต้องการความแม่นยำ เช่น การตัด stock, การโอนเงิน
- ต้องใช้ร่วมกับ
transaction.atomic()เท่านั้นนะ nowait=Trueคือ ถ้า row นั้นถูก lock ไว้ก่อนแล้ว ให้ไม่ต้องรอ + โยน error เลย โดย default มันคือnowait=False(รอ…จนได้ล๊อก หรือ รอจนกว่า row นั้นจะ unlock นั่นแหละ)
from django.db import transaction
with transaction.atomic():
product = Product.objects.select_for_update(nowait=True).get(id=1)
product.stock -= 1
product.save()💡 Use case: Prevent two users from buying the last piece of a product at the same time.
20. defer() / only()
Load only specific fields (useful for performance).
- ใช้เพื่อลดจำนวน field ที่ดึงมาจาก db
- ต่างกันที่ defer = ไม่เอา, only = เอา
defer(‘description’, ‘image’)> ไม่โหลดdescriptionกับimageonly(‘name’, ‘price’)> โหลดเฉพาะnameและpriceเท่านั้น- เพราะ default มันจะ fetches all fields แม้ว่าเราจะไม่ใช้มันก็ตาม ฉะนั้นถ้าอันไหนข้อมูลเยอะ แล้วเราไม่ใช้มันแน่ๆ ก็ไม่ต้องเอามาจะดีกว่านะ
Product.objects.only('name') # Will fetch only 'name' from DB21. reverse()
Reverses the order of a QuerySet. Must follow an order_by().
- แค่เป็นการ reverse() ตัว order_by() เท่านั้นนะ
Product.objects.order_by('price').reverse()22. earliest() / latest()
Returns the object with the earliest or latest date based on a field.
- ได้เป็น object กลับมาเลยนะ
Product.objects.earliest('created_at') # หาข้อมูลที่เก่าสุด เช่น อันแรกสุด
Product.objects.latest('created_at') # หาข้อมูลล่าสุด (ตรงข้ามกับอันบนนะ)23. first() / last()
Returns the first or last object in a QuerySet.
- ได้เป็น object กลับมา ซึ่งคือตัวแรกหรือตัวสุดท้ายจาก queryset
Product.objects.filter(category="Clothing").first()24. count()
Returns the total number of objects in a QuerySet.
Product.objects.count()25. get_or_create()
Tries to get an object, and creates it if it doesn’t exist.
getค่ามาก่อน ถ้าไม่มีค่อยcreateจากdefaults
product, created = Product.objects.get_or_create(name="Bag", defaults={'price': 300})26. update_or_create()
Updates the object if it exists; otherwise, creates it.
updateก่อนถ้ามี แต่ถ้าไม่เจอค่อยcreateจากdefaults
Product.objects.update_or_create(name="Pen", defaults={'price': 35})27. raw()
Executes raw SQL queries.
- สำหรับเขียน SQL เองแทนการใช้ ORM
- เราจะใช้ในกรณีที่ต้องการ optimize เป็นพิเศษ
- แต่ไม่ควรใช้บ่อยนะ เพราะเสี่ยงจาก SQL injection.
Product.objects.raw('SELECT * FROM myapp_product WHERE price > %s', [100])
# มันคือ SELECT * FROM myapp_product WHERE price > 10028. iterator()
Yields results one at a time to save memory — great for big datasets.
- ใช้สำหรับ load ข้อมูลแบบ batch (default = 2000)
- ใช้สำหรับ large data เช่น generate CSV
- เพื่อลด memory usage ของ server เพราะถ้าใช้
.all()กับ large data จะกินแรมเยอะ - พูดให้ง่ายที่สุด ถ้าใช้
User.objects.all(), Django จะโหลด data ทั้งหมดมาเก็บไว้ใน RAM นะ อาจทำให้ server เราเดี้ยงได้เลย ฉะนั้นถ้า data เยอะ ก็ไปใช้iterator()ให้ทยอยๆ ทำงานจ้า
for product in Product.objects.iterator(chunk_size=1000):
print(product.name)29. union(), intersection(), difference()
Set operations between QuerySets.
- union() = เป็นการ combine 2 QuerySet เข้าด้วยกัน (ต้องไม่ซ้ำกันนะ)
q1 = Product.objects.filter(category="Clothing")
q2 = Product.objects.filter(category="Accessories")
combined = q1.union(q2)
# 👉 combined จะได้สินค้าในทั้งหมวด "Clothing" และ "Accessories" รวมกันไม่มีซ้ำกัน- intersection() = หา result ที่อยู่ในทั้ง 2 QuerySet
q1 = Product.objects.filter(price__gt=100)
q2 = Product.objects.filter(stock__gt=0)
common = q1.intersection(q2)
# 👉 common จะได้สินค้าที่ มีราคา > 100 และ stock > 0- defference() = หาค่าที่อยู่ในชุดแรก แต่ไม่อยู่ในชุดหลัง
q1 = Product.objects.filter(category="Clothing")
q2 = Product.objects.filter(price__lt=300)
result = q1.difference(q2)
# 👉 result คือสินค้าที่เป็น "Clothing" แต่ ราคาไม่ต่ำกว่า 30030. db_manager()
Specify which database to use in a multi-database setup.
DATABASES = {
'default': {...},
'replica': {...}
}
# เช่น เห็นไหมว่ามี 2 databaseProduct.objects.db_manager('replica').all()
# 'replica' คือ ชื่อ database ใช้ในกรณีที่ project เรามีหลาย db นั่นเอง31. Q()
Build complex queries using AND, OR, and NOT logic.
from django.db.models import Q
Product.objects.filter(Q(price__lt=100) | Q(category="Accessories"))32. F()
Reference model fields directly in queries (great for comparisons or updates).
F()ใช้เพื่อ อ้างถึงค่าใน field ของ model เดียวกัน ใน query ที่ Django สร้าง- อัปเดตค่าด้วย field เอง
- เปรียบเทียบค่าระหว่าง field
- ลดรอบการ query (efficient มาก)
from django.db.models import F
Product.objects.update(stock=F('stock') - 1)
# นี่จะเป็นการลด stock โดยไม่ต้องดึงค่ามาก่อน
# UPDATE product SET stock = stock - 1 WHERE id = 1;33. Case / When
Add conditional logic inside annotations.
- เป็น Query Expression ที่ทรงพลังอีกตัวนะ สำหรับใส่เงื่อนไขแบบ if-else เลย
- เป็นการเขียน เงื่อนไขแบบ if-elif-else ภายใน
.annotate()หรือ.update()เพื่อใส่ค่าใหม่ลงใน field ที่คำนวณ
from django.db.models import Case, When, Value, CharField
Product.objects.annotate(
status=Case(
When(stock=0, then=Value("Out of stock")),
default=Value("In stock"),
output_field=CharField(),
)
)
# 👉 สิ่งที่ได้คือแต่ละ Product จะมี field status ที่เป็น "In stock" หรือ "Out of stock"
# output_field เพื่อกำหนดให้ตรง type เท่านั้นนะOrder.objects.annotate(
label=Case(
When(total__gt=1000, then=Value("VIP")),
When(total__gt=500, then=Value("Regular")),
default=Value("Newbie"),
output_field=CharField()
)
)Product.objects.update(
label=Case(
When(stock=0, then=Value("Out")),
default=Value("Available")
)
)
# ใช้ใน .update() ก็ได้34. from_queryset()
Define a custom manager using a custom QuerySet.
from_queryset()เป็น วิธีสร้าง custom manager โดยเอา method จาก custom QuerySet มาใส่ให้เลยอัตโนมัติ — ไม่ต้องเขียน method ซ้ำใน Manager อีกครั้ง
✅ ปกติแล้วเขียนแบบนี้ (ยาวหน่อย)
class ProductQuerySet(models.QuerySet):
def cheap(self):
return self.filter(price__lt=100)
class ProductManager(models.Manager):
def cheap(self):
return self.get_queryset().cheap()class ProductQuerySet(models.Q🎉 ถ้าใช้ from_queryset() จะเขียนสั้นลงแบบนี้:
class ProductQuerySet(models.QuerySet):
def cheap(self):
return self.filter(price__lt=100)
class ProductManager(models.Manager.from_queryset(ProductQuerySet)):
pass
class Product(models.Model):
...
objects = ProductManager()✅ ใช้งาน:
Product.objects.cheap()
# 👉 เรียก method cheap() ได้เลยผ่าน .objects โดยไม่ต้อง duplicate logic ใน Manager
# เห็นไหม .cheap() เป็น manager ที่เราสร้างขึ้นมาเองนะ📌 ประโยชน์ของ from_queryset():
- DRY (Don’t Repeat Yourself) — ไม่ต้องเขียนซ้ำ
- ทำให้ method ทั้งหมดใน QuerySet กลายเป็น method ของ Manager อัตโนมัติ
- ช่วยให้แยก logic ออกมาแบบ OOP มากขึ้น
🧠 ใช้เมื่อไหร่?
- เมื่อคุณมีหลาย query logic แบบ reusable (เช่น
.available(),.published(),.vip_only()) - เมื่อคุณอยากทำ queryset chainable เช่น
Product.objects.available().filter(...)
35. Subquery() and OuterRef()
Use values from one query in another — great for advanced filtering or annotations.
from django.db.models import Subquery, OuterRef
latest_order = Order.objects.filter(user=OuterRef('pk')).order_by('-created_at')
User.objects.annotate(last_order_date=Subquery(latest_order.values('created_at')[:1]))36. Exists()
Use to test if a related subquery exists (like .filter().exists() but at DB level).
from django.db.models import Exists, OuterRef
orders = Order.objects.filter(user=OuterRef('pk'))
User.objects.annotate(has_orders=Exists(orders))37. as_manager()
Convert a custom QuerySet into a manager.
class ProductQuerySet(models.QuerySet):
def available(self):
return self.filter(is_available=True)
Product.objects = ProductQuerySet.as_manager()38. select_for_update(nowait=True) / skip_locked=True
Add locking behavior without waiting or skipping locked rows.
nowait=True→ ไม่รอ ถ้าล็อกอยู่ → โยน error ทันทีskip_locked=True→ ข้ามแถวที่ถูกล็อกไปเลย (ดีสำหรับ worker queue)
Product.objects.select_for_update(nowait=True, skip_locked=True)39. select_for_update(of=...) (PostgreSQL only)
Advanced Postgres feature to specify which tables to lock.
Product.objects.select_for_update(of=('self',))40. none()
Returns an empty QuerySet — useful as a default value.
Product.objects.none()Final Thoughts
These QuerySet methods are like tools in your toolbox. You don’t need all of them all the time — but when you do, knowing how to use them can make your Django code cleaner, faster, and more reliable.
If you’re just starting out, pick a few and try using them in your next project. Trust me, Django’s ORM is addictive once you get the hang of it 😄
References:
- https://docs.djangoproject.com/en/5.1/ref/models/querysets/
- Chat เพิ่ลรัก
If you think it’s useful for you, just clap your hands 👏 to be encouraged me.










