Django Rest Framework¶
Integration with Django Rest Framework is provided through a DRF-specific FilterSet
and a filter backend. These may be found in the rest_framework
sub-package.
Quickstart¶
Using the new FilterSet
simply requires changing the import path. Instead of importing from django_filters
, import from the rest_framework
sub-package.
from django_filters import rest_framework as filters
class ProductFilter(filters.FilterSet):
...
Your view class will also need to add DjangoFilterBackend
to the filter_backends
.
from django_filters import rest_framework as filters
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('category', 'in_stock')
If you want to use the django-filter backend by default, add it to the DEFAULT_FILTER_BACKENDS
setting.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
...
),
}
Adding a FilterSet with filter_class
¶
To enable filtering with a FilterSet
, add it to the filter_class
parameter on your view class.
from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product
class ProductFilter(filters.FilterSet):
min_price = django_filters.NumberFilter(name="price", lookup_expr='gte')
max_price = django_filters.NumberFilter(name="price", lookup_expr='lte')
class Meta:
model = Product
fields = ['category', 'in_stock', 'min_price', 'max_price']
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = ProductFilter
Specifying filter_fields
¶
You may bypass creating a FilterSet
by instead adding filter_fields
to your view class. This is equivalent to creating a FilterSet with just Meta.fields.
from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('category', 'in_stock')
# Equivalent FilterSet:
class ProductFilter(filters.FilterSet):
class Meta:
model = Product
fields = ('category', 'in_stock')
Schema Generation with Core API¶
The backend class integrates with DRF’s schema generation by implementing get_schema_fields()
. This is automatically enabled when Core API is installed. Schema generation usually functions seamlessly, however the implementation does expect to invoke the view’s get_queryset()
method. There is a caveat in that views are artificially constructed during schema generation, so the args
and kwargs
attributes will be empty. If you depend on arguments parsed from the URL, you will need to handle their absence in get_queryset()
.
For example, your get queryset method may look like this:
class IssueViewSet(views.ModelViewSet):
queryset = models.Issue.objects.all()
def get_project(self):
return models.Project.objects.get(pk=self.kwargs['project_id'])
def get_queryset(self):
project = self.get_project()
return self.queryset \
.filter(project=project) \
.filter(author=self.request.user)
This could be rewritten like so:
class IssueViewSet(views.ModelViewSet):
queryset = models.Issue.objects.all()
def get_project(self):
try:
return models.Project.objects.get(pk=self.kwargs['project_id'])
except models.Project.DoesNotExist:
return None
def get_queryset(self):
project = self.get_project()
if project is None:
return self.queryset.none()
return self.queryset \
.filter(project=project) \
.filter(author=self.request.user)
Or more simply as:
class IssueViewSet(views.ModelViewSet):
queryset = models.Issue.objects.all()
def get_queryset(self):
# project_id may be None
return self.queryset \
.filter(project_id=self.kwargs.get('project_id')) \
.filter(author=self.request.user)
Crispy Forms¶
If you are using DRF’s browsable API or admin API you may also want to install django-crispy-forms
, which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML. Note that this isn’t actively supported, although pull requests for bug fixes are welcome.
pip install django-crispy-forms
With crispy forms installed and added to Django’s INSTALLED_APPS
, the browsable API will present a filtering control for DjangoFilterBackend
, like so: