PageNumberPagination in Django Rest Framework

Last updated 1 month, 1 week ago | 115 views 75     5

Tags:- Python Django DRF

In RESTful APIs, sending large amounts of data in a single response is inefficient. Pagination solves this by splitting data into manageable "pages." Django Rest Framework (DRF) offers multiple pagination styles, and the most common is PageNumberPagination.

In this article:

  • What PageNumberPagination is

  • How it works

  • How to configure and use it

  • Full code example

  • Tips and common pitfalls


What is PageNumberPagination?

PageNumberPagination is DRF’s simplest pagination class. It divides results into pages and allows clients to access them using a ?page=<number> query parameter.

Example:

GET /api/posts/?page=3

Returns the third page of paginated results.


⚙️ How Pagination Works in DRF

When pagination is enabled:

  • DRF slices your queryset into pages.

  • The response includes metadata like count, next, previous, and results.

  • The client can navigate through pages using query parameters.


Step-by-Step: Using PageNumberPagination

Step 1: Define Pagination Class (Optional)

You can define a custom pagination class to control page size.

# pagination.py
from rest_framework.pagination import PageNumberPagination

class CustomPageNumberPagination(PageNumberPagination):
    page_size = 5
    page_query_param = 'page'  # default
    page_size_query_param = 'size'  # client can override page size
    max_page_size = 100

Step 2: Configure DRF to Use It

In settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'yourapp.pagination.CustomPageNumberPagination',
    'PAGE_SIZE': 10,  # fallback if not set in class
}

Step 3: Use in a View or ViewSet

from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

That’s it! DRF will now return paginated responses automatically.


Example Response

{
  "count": 42,
  "next": "http://localhost:8000/api/posts/?page=3",
  "previous": "http://localhost:8000/api/posts/?page=1",
  "results": [
    {
      "id": 11,
      "title": "Third Page Post 1",
      "content": "..."
    },
    ...
  ]
}

✅ Full Working Example

models.py

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

serializers.py

from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'content']

pagination.py

from rest_framework.pagination import PageNumberPagination

class CustomPageNumberPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'size'
    max_page_size = 50

views.py

from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
from .pagination import CustomPageNumberPagination

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    pagination_class = CustomPageNumberPagination

urls.py

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import PostViewSet

router = DefaultRouter()
router.register('posts', PostViewSet)

urlpatterns = [
    path('api/', include(router.urls)),
]

Tips & Best Practices

Tip Why It Helps
✅ Use page_size_query_param Allows clients to request custom page sizes
✅ Limit max_page_size Prevents abuse by large requests
✅ Test with real data Pagination behaves differently with small datasets
✅ Consider caching Speeds up repeated paginated requests
✅ Return links (next, previous) Great for API consumers like frontend apps

⚠️ Common Pitfalls

Pitfall Solution
❌ Missing pagination class in settings Ensure DEFAULT_PAGINATION_CLASS is set correctly
❌ Confusing page_size and PAGE_SIZE DRF uses the pagination class value first, then PAGE_SIZE as a fallback
❌ Not enough data for testing Add more records to see pages in action
❌ Forgetting to include pagination metadata Always include count, next, previous for good UX

Conclusion

PageNumberPagination is a simple yet powerful way to paginate your API results in Django Rest Framework. It enables efficient, scalable data delivery and integrates seamlessly with DRF's viewsets and routers.

For more complex use cases, also explore:

  • LimitOffsetPagination

  • CursorPagination