How to Filter Model Querysets by a List Using Django’s __in Lookup ?

Introduction

When building web applications with Django, we often need to filter database records based on a list of values—think categories, tags, IDs from a form, or query parameters. Fortunately, Django's ORM makes this easy with the __in lookup.

Let’s walk through how to use this feature effectively in your views.

The Use Case: Filtering on Multiple Values

Suppose you want to retrieve all blog posts tagged with one of several categories, such as "tech", "science", or "education". Rather than chaining multiple filters together, Django provides a much cleaner solution using the __in lookup:

1
q = Post.objects.filter(category__in=['tech', 'science', 'education'])

Django automatically translates this into an efficient SQL IN clause, which is both fast and scalable.

This approach is logically equivalent to writing:

1
2
3
4
q1 = Post.objects.filter(category='tech')
q2 = Post.objects.filter(category='science')
q3 = Post.objects.filter(category='education')
q = q1 | q2 | q3

Both methods return all Post objects where the category field matches one of the specified values. However, while they produce the same results, the two approaches differ significantly in performance, readability, and efficiency:

Aspect __in Lookup Chained Filters with
✅ Performance Translates to a single SQL IN clause (very fast) Executes multiple queries and merges them in Python
✅ Readability Compact and easy to read More verbose and harder to maintain
✅ Simplicity One query, one line Multiple lines and querysets
❌ Flexibility Best for simple matching Allows per-condition customization

Bottom line:
For straightforward filters on a list of values, using __in is the preferred, optimized, and Django-idiomatic approach. Use chained filters only when you need additional logic or customization per condition.

Example: Using __in in a Django View

Here’s how you’d use this in a real-world view:

1
2
3
4
5
6
7
from django.shortcuts import render
from .models import Product

def featured_products(request):
    featured_categories = ['electronics', 'books', 'home']
    products = Product.objects.filter(category__in=featured_categories)
    return render(request, 'products/featured.html', {'products': products})

This returns all products whose category is either "electronics", "books", or "home".

Dynamic Filtering from Query Parameters

You can also make your filters dynamic using GET parameters from the URL:

1
2
3
4
def filter_by_ids(request):
    selected_ids = request.GET.getlist('id')  # e.g., ?id=1&id=2&id=3
    users = User.objects.filter(id__in=selected_ids)
    return render(request, 'users/list.html', {'users': users})

This is extremely useful when filtering from a multi-select input on the frontend.

Tip: Combine with Other Filters

You can combine __in with other filters seamlessly:

1
Event.objects.filter(status='active', location__in=['NY', 'CA'])

This grabs only active events in New York or California.

Don’t Forget: Python-side in Is Different

Sometimes you want to check if a single value is in a Python list—outside the database:

1
2
if user_role in ['admin', 'editor']:
    allow_access = True

This happens in your logic, not in a database query.

Summary

  • Use field__in=[...] to filter Django models against a list.
  • Combine with query parameters for dynamic filters.
  • Use Python’s native in for list checks outside queries.

References

Links Site
in docs.djangoproject.com
Elegant way __in insensitive case forum.djangoproject.com