Chaining querysets lets you combine multiple database queries into one. This helps you get exactly the data you want step by step.
Chaining querysets in Django
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Django
queryset1 = Model.objects.filter(condition1) queryset2 = queryset1.filter(condition2) # You can chain more filters or other queryset methods
Each filter() returns a new queryset, so original querysets stay unchanged.
Querysets are lazy; chaining does not hit the database until you actually use the data.
Examples
Django
books = Book.objects.filter(author='Alice') books = books.filter(published_year=2023)
Django
recent_books = Book.objects.filter(published_year__gte=2020) popular_recent_books = recent_books.filter(rating__gte=4.5)
Django
empty_qs = Book.objects.none() filtered_empty = empty_qs.filter(title__icontains='Python')
Django
all_books = Book.objects.all() first_ten = all_books[:10] filtered_slice = first_ten.filter(genre='Fiction')
Sample Program
This example shows how to chain querysets to narrow down results step by step. First, it gets all books by Alice. Then it chains another filter to get only those published in 2023.
Django
from django.db import models class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) published_year = models.IntegerField() rating = models.FloatField() # Assume we have some Book objects saved in the database # Step 1: Get books by author 'Alice' alice_books = Book.objects.filter(author='Alice') print('Books by Alice:') for book in alice_books: print(f'- {book.title} ({book.published_year})') # Step 2: Chain to get books by Alice published in 2023 alice_books_2023 = alice_books.filter(published_year=2023) print('\nBooks by Alice published in 2023:') for book in alice_books_2023: print(f'- {book.title}')
Important Notes
Chaining querysets is efficient because Django combines all filters into one database query.
Querysets are lazy, so no database hit happens until you iterate or convert to list.
Common mistake: slicing a queryset returns a list, which cannot be chained further.
Summary
Chaining querysets lets you build complex queries step by step.
Each filter returns a new queryset without changing the original.
Be careful not to slice before filtering, or chaining will break.
Practice
1. What does chaining querysets in Django allow you to do?
easy
Solution
Step 1: Understand queryset chaining
Chaining querysets means applying filters or other queryset methods one after another, each returning a new queryset.Step 2: Effect on original queryset
Each filter returns a new queryset and does not modify the original queryset, allowing step-by-step building.Final Answer:
Build complex database queries step by step without changing the original queryset -> Option CQuick Check:
Chaining querysets = build stepwise [OK]
Hint: Remember: filters return new querysets, original stays unchanged [OK]
Common Mistakes:
- Thinking filters modify the original queryset
- Believing chaining runs multiple queries simultaneously
- Confusing queryset chaining with saving data
2. Which of the following is the correct way to chain querysets in Django?
easy
Solution
Step 1: Check chaining syntax
Chaining querysets means applying filters or other queryset methods one after another, returning new querysets.Step 2: Identify invalid methods
Methods likesave()andupdate()are not queryset chaining methods;get()returns a single instance, not suitable for chaining.Final Answer:
MyModel.objects.filter(active=True).exclude(age__lt=18) -> Option AQuick Check:
Correct chaining uses filter/exclude methods [OK]
Hint: Chain filters and excludes; avoid save() or update() in chaining [OK]
Common Mistakes:
- Using save() or update() in queryset chains
- Using get() after filters
- Confusing queryset methods with model instance methods
3. Given the code:
What does
qs = MyModel.objects.filter(active=True) qs2 = qs.filter(age__gte=18) qs3 = qs2.exclude(name__startswith='A')
What does
qs3 contain?medium
Solution
Step 1: Analyze first filter
qsfilters objects whereactive=True.Step 2: Analyze second filter
qs2further filtersqsto include only those withage >= 18.Step 3: Analyze exclude
qs3excludes objects fromqs2whosenamestarts with 'A'.Final Answer:
Active MyModel objects aged 18 or older whose names do not start with 'A' -> Option AQuick Check:
Filters + exclude = refined queryset [OK]
Hint: Read filters stepwise to understand final queryset content [OK]
Common Mistakes:
- Ignoring the exclude step
- Mixing up filter and exclude logic
- Assuming qs3 includes names starting with 'A'
4. What is wrong with this queryset chaining?
qs = MyModel.objects.all()[:10] qs = qs.filter(active=True)
medium
Solution
Step 1: Understand slicing effect
Slicing a queryset (like[:10]) evaluates it and returns a list, not a queryset.Step 2: Applying filter after slicing
Sinceqsis now a list, callingfilter()on it causes an error or unexpected behavior.Final Answer:
Slicing before filtering breaks chaining; filter cannot be applied after slicing -> Option DQuick Check:
Slice first = no chaining [OK]
Hint: Always filter before slicing to keep queryset chaining intact [OK]
Common Mistakes:
- Slicing before filtering
- Assuming slicing returns a queryset
- Trying to chain after slicing
5. You want to get all active users aged 18 or older, but exclude those whose names start with 'A' or 'B'. Which queryset chaining is correct?
hard
Solution
Step 1: Filter active and age
Use two filters or one combined filter to get active users aged 18 or older.Step 2: Exclude names starting with 'A' and 'B'
Exclude separately for 'A' and 'B' becauseexclude(name__startswith='A' or 'B')is invalid syntax andexclude(name__startswith=['A', 'B'])is not supported.Final Answer:
MyModel.objects.filter(active=True).filter(age__gte=18).exclude(name__startswith='A').exclude(name__startswith='B') -> Option BQuick Check:
Chain filters then multiple excludes correctly [OK]
Hint: Chain filters first, then exclude each condition separately [OK]
Common Mistakes:
- Using invalid exclude syntax with 'or' inside
- Trying to exclude with a list in startswith
- Mixing filter and exclude order incorrectly
