When building APIs, you often deal with large datasets, and filtering is a must to allow users to retrieve only the data they need. Filtering in APIs allows users to search and narrow down results based on specific criteria. Thankfully, Django REST Framework (DRF) makes this process straightforward with the help of Django-filter, a powerful package that allows for flexible and efficient filtering.
In this blog post, we’ll walk through building an API with filtering using a real-world example. We’ll use Django-filter to handle common filtering operations, including searching by name, filtering by tech stack, and using date ranges. By the end, you’ll have a solid understanding of implementing filtering in your APIs.
Table of Contents:
- The Problem We're Solving
- Setting Up the Project
- Project Initialization
- Installing Django-filter
- Building the Models
- Creating the API Views
- Implementing Filtering with Django-filter
- Testing the API
- Conclusion
The Problem We're Solving
Imagine you’re building a project management application where users can create and manage projects. Users need to:
- Search for projects by name.
- Filter projects by tech stack (e.g., Python, JavaScript).
- Retrieve projects created within a specific date range.
We’ll build an API to handle these requests efficiently using Django REST Framework and Django-filter
.
Setting Up the Project
Project Initialization
First, let's set up a Django project. Open your terminal and run the following commands:
Now, add the project's app to INSTALLED_APPS in project_management/settings.py:
INSTALLED_APPS = [
# Django default apps
'rest_framework',
'django_filters', # Adding django-filter
'projects', # Our project app
]
Configure DRF to use DjangoFilterBackend by adding this to settings.py:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10, # Limit results per page to 10
}
DjangoFilterBackend is the bridge between DRF and Django-filters, allowing you to use the powerful filtering capabilities of Django-filters in your DRF views.
Adding DjangoFilterBacked will allow all views that use the default filter backend to support filtering using the DjangoFilterBackend.
Building the Models
In the real world, project management systems often have models like Project and Category. Let’s create a Project model where each project has a name, description, tech stack, and creation date.
In projects/models.py, add the following code:
from django.db import models
class Project(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
tech_stack = models.CharField(max_length=255) # e.g., Python, JavaScript
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
We now have a basic model to store project information. Each project has a name, description, tech_stack (which lists technologies like Python, Django, etc.), and a created_at field to track when the project was added.
Next, we’ll create a migration and apply it:
python manage.py makemigrations
python manage.py migrate
We now have the basic Project model set up in our database.
Let’s add some sample data into our Project model. You can create this data directly in your Django shell or by using the Django admin.
Step 1: Open Django Shell
python manage.py shell
Step 2: Add Sample Data
from projects.models import Project
from datetime import datetime
# Sample data
Project.objects.create(name="Alpha Project", description="A project management tool.", tech_stack="Python, Django", created_at=datetime(2023, 1, 15))
Project.objects.create(name="Beta System", description="An inventory system.", tech_stack="Java, Spring Boot", created_at=datetime(2023, 2, 10))
Project.objects.create(name="Gamma Build", description="A continuous integration tool.", tech_stack="Python, Docker", created_at=datetime(2023, 3, 20))
Project.objects.create(name="Delta Tracker", description="A time tracking tool.", tech_stack="Node.js, Express", created_at=datetime(2023, 4, 25))
Now we have four projects in our database, each with different tech stacks and creation dates. These will serve as our test data for the filtering functionality.
Creating the API Views
Let’s define an API that allows users to:
- Retrieve a list of all projects.
- Search for projects by name.
- Filter projects by tech stack or creation date.
First, let's create a serializer in projects/serializers.py
to convert Project instances into JSON:
from rest_framework import serializers
from .models import Project
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ['id', 'name', 'description', 'tech_stack', 'created_at']
Now, let’s define an API view to list all projects. Open projects/views.py and create a simple view using Django REST Framework’s ListAPIView:
from rest_framework import generics
from .models import Project
from .serializers import ProjectSerializer
class ProjectListView(generics.ListAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
Next, Create and add the route for this view in projects/urls.py:
from django.urls import path
from .views import ProjectListView
urlpatterns = [
path('projects/', ProjectListView.as_view(), name='project-list'),
]
Include this in your main urls.py file:
from django.urls import path, include
urlpatterns = [
path('api/', include('projects.urls')),
]
Now, you can run the server python manage.py runserver
and visit /api/projects/
to see the list of all projects we created.
But there’s no filtering yet, so let’s fix that next!
Implementing Filtering with Django-filter
To add filtering, we’ll use Django-filter’s FilterSet to allow users to search by project name, and tech stack, and filter by creation date.
Step 1: Define a FilterSet
Create a filter class in projects/filters.py:
import django_filters
from .models import Project
class ProjectFilter(django_filters.FilterSet):
name = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
tech_stack = django_filters.CharFilter(field_name='tech_stack', lookup_expr='icontains')
class Meta:
model = Project
fields = ['name', 'tech_stack', 'created_at']
This defines a custom filter class called ProjectFilter. The filter class extends django_filters.FilterSet
, a base class provided by django-filter
to define filters for a particular model.
In this class:
Two filters are defined: name and tech_stack
.
name = django_filters.CharFilter(...)
: This defines a filter for the name field.
field_name='name'
: This tells the filter to target the name field in the Project model.lookup_expr='icontains'
: This sets the lookup expression toicontains
, this will filter for case-insensitive, partial matches on the name field. For example, searching for "alpha" will match project names like "Alpha Project", "alpha beta" or "ALPHA".
tech_stack = django_filters.CharFilter(...)
: This filter targets the tech_stack field and applies the same logic:
field_name='tech_stack'
: This tells the filter to target the tech_stack field in the Project model.lookup_expr='icontains'
: This allows for case-insensitive, partial matching on the tech_stack field. Searching for "Python" will match any tech stack that includes "Python," " Django," or "React, Python."
The Meta class provides additional configuration for the ProjectFilter.
model = Project
: This tells the filter that it is based on the Project model, meaning the filtering logic will be applied to the Project table in the database.fields = ['name', 'tech_stack', 'created_at']
: This defines the fields in the Project model that can be filtered. Learn more about django-filter here
Step 2: Add Filtering to the View
Now, update your ProjectListView to use filtering:
from django_filters.rest_framework import DjangoFilterBackend
from .filters import ProjectFilter
class ProjectListView(generics.ListAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
filter_backends = [DjangoFilterBackend] # Enable filtering
filterset_class = ProjectFilter # Use our custom filter
Testing the API
Let’s test the filtering functionality using some of the examples we created above.
Example 1: Searching by Project Name
To search for projects with "alpha" in their name, you can use this URL:
/api/projects/?name=alpha
Example 2: Filtering by Tech Stack
You can filter projects based on the technologies used in their tech stack. For example:
/api/projects/?tech_stack=Python
Conclusion
In this blog post, we’ve seen how to build an API with filtering in Django REST Framework using Django-filter
. We covered how to:
- Set up a project and create a basic API.
- Implement search and filtering by name, and tech stack using FilterSet.
- Test the filtering functionality with sample data.
By leveraging Django-filter you can offer efficient filtering options in your APIs with minimal effort. This helps reduce the load on your database, ensures faster queries, and provides a more tailored user experience.
Link for Further reading:
Django-filter official documentation
Djangorestframework
Link to example code: Filtering-in-Django-REST-Framework
Top comments (0)