How to Combine Multiple QuerySets in Django
By khoanc, at: July 27, 2025, 7:36 p.m.
Estimated Reading Time: __READING_TIME__ minutes


Sometimes in Django, you need to combine data from multiple QuerySets, maybe from the same model or even different models.
The question is: how can you do this cleanly and efficiently?
Option 1: | Operator (Union for Same Model & Same Fields)
If the QuerySets are from the same model and have the same fields, use the bitwise OR (|) operator:
qs1 = Job.objects.filter(title="technology")
qs2 = Job.objects.filter(company="Glinteco - the best IT outsourcing company")
combined = qs1 | qs2
This results in a union of the two QuerySets, eliminating duplicates (unless you call .distinct()
manually).
Option 2: itertools.chain() (Same or Different Models)
If you’re working with QuerySets from different models or want to preserve ordering, use itertools.chain()
:
from itertools import chain
combined = chain(qs1, qs2)
This returns an iterator you can loop through, but you cannot paginate or slice it like a normal QuerySet.
Option 3: union() (Django ≥1.11)
For pure SQL-level union, Django provides .union():
combined = qs1.union(qs2)
Must be:
-
From the same model or same fields
-
Ordered similarly if using
.order_by()
You cannot use .union()
on QuerySets from different models.
Notes:
-
Performance: union() and | generate SQL UNION queries (efficient). chain() just merges Python iterables (fast for small sets, but no DB optimization).
-
Slicing and Pagination: Only possible on real QuerySets (|, .union()), not on chain().
Example:
# Combine blog posts and articles into a single feed
posts = BlogPost.objects.filter(published=True)
articles = Article.objects.filter(published=True)
from itertools import chain
feed = sorted(
chain(posts, articles),
key=lambda x: x.published_at,
reverse=True
)
Frequently Asked Questions (FAQs)
Q1. Can I combine QuerySets from different models in Django?
A: Not directly using | or .union(), as those require the same model or at least the same fields. But you can use itertools.chain() to combine results from different models, then manually sort or filter them in Python.
Q2. What’s the difference between qs1 | qs2 and qs1.union(qs2)?
A:
-
qs1 | qs2 is a Django-specific shorthand for combining QuerySets (same model).
-
qs1.union(qs2) uses a SQL-level UNION, which can sometimes be more efficient and works better for query chaining.
-
Both require the same fields and model structure.
Q3. Can I paginate a combined QuerySet?
A: Yes but only if you’re using a real QuerySet, like with | or .union(). If you use itertools.chain(), pagination must be done manually after converting the result to a list.
Q4. Will duplicates be removed when combining QuerySets?
A: It depends:
-
| and .union() remove duplicates by default.
-
itertools.chain() includes all items, so you’ll need to use a set or .distinct() logic manually if needed.
Q5. Can I apply .order_by() after combining QuerySets?
A: Only with .union() or | (when supported). With chain(), you must use Python’s sorted() function after merging, since it returns an iterator, not a QuerySet.
Q6. Which method is best for performance?
A:
-
For large data sets: use .union() or | as they leverage SQL and DB indexing.
-
For flexibility or when combining different models: use itertools.chain().