Better filtering for Django REST Framework
djangorestframework-filters (DRF-Filters) provides a more powerful and flexible filtering solution for Django REST Framework. It extends `django-filter` to integrate seamlessly with DRF, offering features like related field filtering, method-based filtering, and lookup customization. The current stable version is 0.11.1, with active development on a future 1.0.0 release, while 0.x continues to receive maintenance updates.
Common errors
-
TypeError: __init__() missing 1 required positional argument: 'queryset'
cause Using `rest_framework_filters.RelatedFilter` in version 0.10.0 or later without providing the required `queryset` argument.fixAdd `queryset=YourRelatedModel.objects.all()` to your `RelatedFilter` instance. For example: `author = RelatedFilter(AuthorFilter, field_name='author', queryset=Author.objects.all())`. -
AttributeError: 'RestFrameworkFilterBackend' object has no attribute 'get_filterset'
cause The `filter_backends` attribute on your `ViewSet` is missing or incorrectly configured, or the `filterset_class` attribute is missing.fixEnsure your `ViewSet` includes `filter_backends = (RestFrameworkFilterBackend,)` and `filterset_class = YourFilterSetClass`. -
django.core.exceptions.FieldError: Cannot resolve keyword 'related_field_name' into field.
cause Incorrect `field_name` or `lookups` specified in `RelatedFilter` or standard `Filter` definitions, or attempting to filter on a non-existent lookup for a field.fixDouble-check that the `field_name` matches an actual field or relationship on your model, and that the `lookups` specified (e.g., `['exact', 'icontains']`) are valid for the field type.
Warnings
- breaking The `queryset` argument for `rest_framework_filters.RelatedFilter` became a required argument.
- deprecated The `MethodFilter` class was deprecated. Its functionality was absorbed directly into the base `Filter` class.
- breaking Compatibility with `django-filter` underwent significant changes. Versions `0.9.x` were locked to `django-filter<1.0`, while versions `0.10.x` and later require `django-filter>=1.0.0`.
- gotcha `AllLookupsFilter` can inadvertently override explicitly declared filters in a `FilterSet` if they share the same field name.
Install
-
pip install djangorestframework-filters
Imports
- RestFrameworkFilterBackend
from rest_framework_filters.backends import RestFrameworkFilterBackend
- FilterSet
from rest_framework_filters import FilterSet
- RelatedFilter
from rest_framework_filters import RelatedFilter
- AllLookupsFilter
from rest_framework_filters import AllLookupsFilter
Quickstart
import os
from django.db import models
from rest_framework import serializers, viewsets
from rest_framework_filters import FilterSet, RelatedFilter
from rest_framework_filters.backends import RestFrameworkFilterBackend
# --- Minimal Django setup for demonstration (not for production) ---
# from django.conf import settings
# settings.configure(INSTALLED_APPS=['django.contrib.auth', 'django.contrib.contenttypes', 'rest_framework', 'rest_framework_filters'], DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}})
# import django
# django.setup()
# --- 1. Define your Models ---
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
published_year = models.IntegerField()
def __str__(self):
return f'{self.title} by {self.author.name}'
# --- 2. Define your FilterSet ---
class AuthorFilter(FilterSet):
class Meta:
model = Author
fields = ['name']
class BookFilter(FilterSet):
# Filter by author name (related field)
author = RelatedFilter(AuthorFilter, field_name='author', queryset=Author.objects.all())
class Meta:
model = Book
fields = {
'title': ['iexact', 'icontains'],
'published_year': ['exact', 'gte', 'lte'],
}
# --- 3. Define your Serializers ---
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True)
class Meta:
model = Book
fields = '__all__'
# --- 4. Define your ViewSets with filter_backends ---
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = (RestFrameworkFilterBackend,)
filterset_class = BookFilter
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
filter_backends = (RestFrameworkFilterBackend,)
filterset_class = AuthorFilter
# Example usage (assuming Django/DRF setup):
# from rest_framework.test import APIClient
# client = APIClient()
# # Assuming you have data created, e.g., Author.objects.create(name='Jane Doe')
# # response = client.get('/books/?author__name=Jane') # This would work if DRF endpoints were configured.
# # print(response.data)