Django-filter is a reusable Django application for allowing users to filter querysets dynamically. It uses a CalVer versioning scheme (Year.ReleaseNumber) and aims to support all current Django versions, matching Python versions, and the latest Django REST Framework.
Install & Compatibility
Where this runs
tested against v25.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.930 runs
installs and imports cleanly · install 0.0s · import 0.707s · 66.9MB
glibcpy 3.10–3.930 runs
installs and imports cleanly · install 3.4s · import 0.651s · 67MB
66MB installed
● package 66MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
FilterSet
✓ from django_filters import FilterSet
✗ import django_filters
Filter
✓ from django_filters import Filter
CharFilter
✓ from django_filters import CharFilter
This quickstart demonstrates defining a `FilterSet` for a Django model and integrating it with a standard Django class-based view (`ListView`) and a Django REST Framework `generics.ListAPIView`. For DRF, `DjangoFilterBackend` is added to `filter_backends` and the `filterset_class` or `filterset_fields` is specified on the view. Remember to add `django_filters` and `rest_framework` to `INSTALLED_APPS` in your Django `settings.py`.
import django_filters
from django.db import models
from django.views.generic import ListView
from rest_framework import generics
from rest_framework import serializers
from django_filters.rest_framework import DjangoFilterBackend
# 1. Define a Django Model
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=5, decimal_places=2)
release_date = models.DateField(null=True, blank=True)
in_stock = models.BooleanField(default=True)
def __str__(self):
return self.name
class Meta:
app_label = 'myapp' # Required for models in standalone snippets
# 2. Define a FilterSet for the Model
class ProductFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains')
price_gt = django_filters.NumberFilter(field_name='price', lookup_expr='gt')
price_lt = django_filters.NumberFilter(field_name='price', lookup_expr='lt')
class Meta:
model = Product
fields = ['name', 'price', 'release_date', 'in_stock']
# 3. Use with a Django Class-Based View
# (Requires Django URL configuration and template setup)
class ProductListView(ListView):
model = Product
template_name = 'product_list.html' # Dummy template for example
context_object_name = 'products'
def get_queryset(self):
queryset = super().get_queryset()
filter = ProductFilter(self.request.GET, queryset=queryset)
return filter.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = ProductFilter(self.request.GET, queryset=self.get_queryset())
return context
# 4. Use with Django REST Framework
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductAPIView(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = ProductFilter # Or filterset_fields = ['name', 'price'] for simpler cases
# To run this code, you would need:
# - A Django project and app ('myapp').
# - Add 'django_filters' and 'rest_framework' to INSTALLED_APPS in settings.py.
# - Define URL patterns for ProductListView and ProductAPIView.
# - Run migrations to create the Product model.
# - Optionally, create 'product_list.html' template for the ListView.
Debug
Known issues
breakingVersion 2.0 introduced several breaking changes, including the removal of the list form for `Filter.lookup_expr`, the `filter_for_reverse_field` method, and `FilterSet Meta.together`. View attributes like `filter_class` were renamed to `filterset_class`, and `FilterSet` strictness handling was moved to the view layer.fixConsult the official migration guide for 2.0 to update your code.
affects: <2.0.0
gotchaA regression in version 2.0 incorrectly caused `FilterView` to use an empty `QuerySet` when the `FilterSet` was unbound (no GET parameters). This was fixed in 2.1.0. A common workaround was setting `strict=False` on the `FilterSet`, which is no longer necessary after the fix.fixUpgrade to 2.1.0 or later. If on 2.0.0, ensure `strict=False` on affected `FilterSet`s if you observe empty querysets for unbound filters.
affects: 2.0.0
breakingThe in-built API schema generation methods of `DjangoFilterBackend` were deprecated in v23.2 and subsequently removed in v25.1.fixMigrate to `drf-spectacular` for generating OpenAPI schemas with Django REST Framework.
affects: >=25.1
breakingSupport for Python and Django versions is dropped when they reach end-of-life. For example, Python 3.8 support was dropped in v25.1.fixRegularly update your Python and Django versions to supported releases as per the official `django-filter` and Django EOL policies. Check `django-filter` documentation for current supported versions.
affects: Varies by EOL policy
gotchaFor text search filters (`CharField`, `TextField`), it's a common mistake to forget to set `lookup_expr` (e.g., to `icontains` for partial, case-insensitive matches). The default lookup is `exact`, which may lead to unexpected 'no results' for partial searches.fixExplicitly define `lookup_expr='icontains'` (or similar) on `CharFilter` and `TextFilter` instances when partial text matching is desired. Example: `name = django_filters.CharFilter(lookup_expr='icontains')`.
affects: All versions
gotchaFiltering by truly empty string values is not directly supported, as empty values in query parameters are typically interpreted as 'skipped filter'.fixImplement a custom filter method or use 'magic values' in your query parameters to explicitly signal an empty string filter, as described in the official documentation under 'Filtering by empty values'.
affects: All versions
securityA `MaxValueValidator` was added to the form field for `NumberFilter` in version 2.4.0 to prevent potential DoS attacks from very large exponents being converted to integers.fixUpgrade to 2.4.0 or later. If upgrading is not immediately possible, consider implementing custom validation on `NumberFilter` fields to limit maximum values. The default limit is `1e50` and can be customized via `NumberFilter.get_max_validator()`.
affects: <2.4.0
gotchaWhen integrating `django-filter` with Django REST Framework, the `djangorestframework` package must be installed. Attempting to import `rest_framework` components without it will result in a `ModuleNotFoundError`.fixInstall the `djangorestframework` package using pip: `pip install djangorestframework`.
affects: All versions
breakingWhen using `django-filter` with Django REST Framework functionality (e.g., `rest_framework.generics`), `djangorestframework` must be installed. A `ModuleNotFoundError` for `rest_framework` indicates this dependency is missing.fixInstall `djangorestframework` in your project environment (e.g., `pip install djangorestframework`). Ensure it's listed in your project's dependencies.
affects: All versions
Audit
Dependencies
DjangorequiredCore dependency for any django-filter usage.
djangorestframeworkoptionalRequired for Django REST Framework integration.