django-filter
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.
Warnings
- breaking Version 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.
- gotcha A 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.
- breaking The in-built API schema generation methods of `DjangoFilterBackend` were deprecated in v23.2 and subsequently removed in v25.1.
- breaking Support for Python and Django versions is dropped when they reach end-of-life. For example, Python 3.8 support was dropped in v25.1.
- gotcha For 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.
- gotcha Filtering by truly empty string values is not directly supported, as empty values in query parameters are typically interpreted as 'skipped filter'.
- security A `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.
Install
-
pip install django-filter
Imports
- FilterSet
import django_filters class MyFilter(django_filters.FilterSet):
- CharFilter
import django_filters my_field = django_filters.CharFilter(...)
- DjangoFilterBackend
from django_filters.rest_framework import DjangoFilterBackend
Quickstart
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.