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

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)