DEV Community

Cover image for How to Build a Task Manager API with Django REST Framework: Part 5 - Optimizing API Performance: Filtering, Pagination & Search
kihuni
kihuni

Posted on • Edited on

How to Build a Task Manager API with Django REST Framework: Part 5 - Optimizing API Performance: Filtering, Pagination & Search

Welcome back to our Django REST Framework (DRF) tutorial series! We set up Django and DRF in Part 1. Part 2 added CRUD for tasks, Part 3 secured it with token authentication, and Part 4 personalized it with user-owned tasks. In Part 5, we’re optimizing our Task Manager API with filtering, pagination, and search—making it user-friendly for large datasets.

By the end, your API will let users filter tasks by status, paginate results, and search by title, all tested with Postman. Ready to level up?

Let’s dive in!

Table of Contents

Step 1: Install and Configure django-filter

We’ll use django-filter to add filtering capabilities to our API.

Install django-filter
Run this command to install the package:

pip install django-filter 
Enter fullscreen mode Exit fullscreen mode

Update taskmanager/settings.py

Add django_filters to INSTALLED_APPS and configure DRF to use it:

INSTALLED_APPS = [ ... 'django.contrib.auth', 'django.contrib.contenttypes', 'rest_framework', 'rest_framework.authtoken', 'tasks', 'django_filters', # New ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), } 
Enter fullscreen mode Exit fullscreen mode
  • django_filters enables filtering by adding query parameters (e.g., ?completed=true).
  • DEFAULT_FILTER_BACKENDS tells DRF to use DjangoFilterBackend globally.

Step 2: Add Filtering to Views

Let’s allow users to filter tasks by completed status, respecting user ownership.

Update tasks/views.py

Modify the TaskListCreateView to include filtering:

from rest_framework import generics from rest_framework.permissions import IsAuthenticated from rest_framework.authentication import TokenAuthentication from django_filters.rest_framework import DjangoFilterBackend from .models import Task from .serializers import TaskSerializer class TaskListCreateView(generics.ListCreateAPIView): serializer_class = TaskSerializer permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] filter_backends = [DjangoFilterBackend] # Enable filtering filterset_fields = ['completed'] # Allow filtering by completed status def get_queryset(self): # Only show tasks created by the authenticated user return Task.objects.filter(created_by=self.request.user) def perform_create(self, serializer): # Automatically set the creator when a task is created serializer.save(created_by=self.request.user) class TaskDetailView(generics.RetrieveUpdateDestroyAPIView): serializer_class = TaskSerializer permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] def get_queryset(self): # Only allow access to tasks created by the authenticated user return Task.objects.filter(created_by=self.request.user) 
Enter fullscreen mode Exit fullscreen mode

What changed?

  • Added filter_backends = [DjangoFilterBackend] to enable filtering.
  • Set filterset_fields = ['completed'] to allow filtering by the completed field.

Step 3: Implement Pagination

Let’s add pagination to limit the number of tasks returned per request.

Update taskmanager/settings.py

Configure DRF’s default pagination:

REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10, # Number of items per page } 
Enter fullscreen mode Exit fullscreen mode
  • PageNumberPagination adds a page and page_size query parameters (e.g., ?page=2&page_size=5).
  • PAGE_SIZE sets the default number of items per page (overridable by clients).

Note: No changes are needed in views.py—pagination is handled automatically

Step 4: Add Search Functionality

Let’s enable searching tasks by title.
Update tasks/views.py

Add search to TaskListCreateView

from rest_framework import generics from rest_framework.permissions import IsAuthenticated from rest_framework.authentication import TokenAuthentication from django_filters.rest_framework import DjangoFilterBackend from .models import Task from .serializers import TaskSerializer class TaskListCreateView(generics.ListCreateAPIView): serializer_class = TaskSerializer permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] filter_backends = [DjangoFilterBackend] # Filtering filterset_fields = ['completed'] # Filtering by completed search_fields = ['title'] # Enable search by title def get_queryset(self): # Only show tasks created by the authenticated user return Task.objects.filter(created_by=self.request.user) def perform_create(self, serializer): # Automatically set the creator when a task is created serializer.save(created_by=self.request.user) class TaskDetailView(generics.RetrieveUpdateDestroyAPIView): serializer_class = TaskSerializer permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] def get_queryset(self): # Only allow access to tasks created by the authenticated user return Task.objects.filter(created_by=self.request.user) 
Enter fullscreen mode Exit fullscreen mode

Added search_fields = ['title'] to enable searching by the title field using the ?search= query parameter.

Step 5: Test with Postman

Start your server:

python manage.py runserver 
Enter fullscreen mode Exit fullscreen mode

We’ll use Postman to test filtering, pagination, and search.

1. Register a User and Add Multiple Tasks

Register User:

{ "username": "newUser1", "password": "pass123" } 
Enter fullscreen mode Exit fullscreen mode

Send. Copy the token (e.g., bc54e0e61096a8c79d2c5c6d958b2d3ed5fda519).

Log In:

{ "username": "newUser1", "password": "pass123" } 
Enter fullscreen mode Exit fullscreen mode

Expect {"token": "bc54e0e61096a8c79d2c5c6d958b2d3ed5fda519"}.

Add Tasks:

{"title": "Task 1", "description": "First task", "completed": false} {"title": "Task 2", "description": "Second task", "completed": true} {"title": "Task 3", "description": "Third task", "completed": false} 
Enter fullscreen mode Exit fullscreen mode

Send each. Expect 201 Created

postman

2. Test Filtering

Filter Completed Tasks:

Send. Expect 200 OK with [{"title": "Task 2", ...}].

filtering

Filter Uncompleted Tasks:

Send. Expect 200 OK with [{"title": "Task 1", ...}, {"title": "Task 3", ...}].

filtering

3. Test Pagination

Default Pagination:

Send. Expect 200 OK with up to 10 tasks (e.g., {"count": 3, "next": null, "previous": null, "results": [...]}).

pagination

Custom Page Size:

Send. Expect 200 OK with 2 tasks per page (e.g., first page with Task 1 and Task 2).

pagination

4. Test Search

Search by Title:

Send. Expect 200 OK with all tasks containing "Task" in the title (e.g., all three tasks).

searching

Specific Search:
URL: http://127.0.0.1:8000/api/tasks/?search=Task 1

Send. Expect 200 OK with [{"title": "Task 1", ...}].

Searching

5. Combine Features

Filter and Paginate:

Send. Expect 200 OK with one uncompleted task (e.g., Task 1).

combined search

Conclusion

🎉 Great job! Your Task Manager API now handles filtering by completed status, paginates results for scalability, and searches by title—making it efficient and user-friendly. These optimizations build on the user-owned tasks from Part 4, keeping your API secure and user-friendly.

Summary Checklist

  • ✅Installed and configured django-filter
  • ✅Added filtering to views
  • ✅Implemented pagination
  • ✅Added search functionality
  • ✅Tested with Postman

What’s Next?

Part 6 covers API security best practices. Stay tuned!

Top comments (0)