Django
QuerySets
Database
Python
Web Development

How to combine multiple QuerySets in Django?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Combining QuerySets in Django can mean several different things: applying an OR filter to one model, uniting two QuerySets that return compatible rows, or chaining already-evaluated results in Python. The right approach depends on whether the combination should happen in SQL or in Python after the data has been fetched.

For most same-model filtering tasks, the best answer is to keep the work in the database using Q objects or compatible QuerySet operators. Python-level combination is usually the fallback, not the default.

Combine Conditions With Q

If you are really combining criteria on the same model, Q objects are often the cleanest approach.

python
1from django.db.models import Q
2from books.models import Book
3
4qs = Book.objects.filter(
5    Q(author="Author A") | Q(author="Author B")
6)

This produces one SQL query with an OR condition. It is usually better than building multiple QuerySets and combining them later.

Use the | Operator for Compatible QuerySets

Django also allows combining compatible QuerySets of the same model with |.

python
qs1 = Book.objects.filter(author="Author A")
qs2 = Book.objects.filter(author="Author B")
combined = qs1 | qs2

This is convenient, but conceptually it is still about building a database-level union of compatible conditions on the same model.

If what you really want is “author is A or B,” a single filter with Q is often clearer.

Use union() for Compatible Result Sets

If you need SQL set union behavior, Django provides union().

python
qs1 = Book.objects.filter(published=True).values_list("title")
qs2 = Book.objects.filter(featured=True).values_list("title")
combined = qs1.union(qs2)

This works best when the selected columns are compatible across the participating QuerySets.

It is a stronger SQL-style operation than simply expressing OR logic.

Chain Results in Python When the Models Differ

If the QuerySets come from different models, database-level combination is usually not possible in the same direct way. In that case, you may need to combine the results in Python.

python
1from itertools import chain
2
3articles = Article.objects.filter(published=True)
4videos = Video.objects.filter(published=True)
5results = list(chain(articles, videos))

This is fine when you truly need heterogeneous objects, but note that this is no longer a lazy database QuerySet in the Django sense. Once you chain and list the results, you are working with Python objects in memory.

Preserve Laziness When You Can

One of Django QuerySet’s strengths is lazy evaluation. If you convert everything to a list too early, you lose:

  • database-level optimization
  • lazy slicing
  • later filtering or ordering in SQL

That is why you should keep the combination in the ORM when possible and drop to Python only when the data model actually requires it.

Ordering and Distinct Behavior

When combining QuerySets, pay attention to ordering and duplicates.

For example, an OR condition may naturally include rows that satisfy both sides. Depending on the operation, you may need distinct().

python
qs = Book.objects.filter(
    Q(author="Author A") | Q(title__icontains="Django")
).distinct()

Whether this is necessary depends on the joins and filters involved.

Common Pitfalls

A common mistake is using Python-level chain when the combination could have been done in SQL more efficiently.

Another mistake is trying to combine QuerySets from different models as if Django could always treat them as one queryable object. Usually it cannot.

Developers also sometimes use the | operator without asking whether a single Q(...) expression would be clearer.

Finally, once you materialize results into a list, you no longer have a real QuerySet with lazy ORM behavior. That tradeoff should be intentional.

Summary

  • Use Q objects when the real need is one query with combined conditions.
  • Use | for compatible same-model QuerySets when that syntax is clearer.
  • Use union() for SQL set-union style combinations of compatible result sets.
  • Use Python-level chain only when database-level combination is not the right model.
  • Prefer keeping the work in the database until you have a reason not to.

Course illustration
Course illustration

All Rights Reserved.