CursorPagination in Django Rest Framework

Last updated 4 months, 2 weeks ago | 409 views 75     5

Tags:- Python Django DRF

As your datasets grow and users scroll endlessly through results, pagination becomes critical—not just for performance but for a seamless experience. CursorPagination is DRF’s most stable and secure pagination class, ideal for large or frequently changing datasets.

This article covers:

  • What CursorPagination is

  • How it works

  • How to configure and implement it

  • A complete example

  • Tips & best practices

  • Common pitfalls


What is CursorPagination?

CursorPagination is a position-based pagination system. Unlike offset-based or page-based methods, it doesn’t rely on arbitrary numbers. Instead, it uses an encoded cursor that includes a position and ordering.

This makes it:

✅ Stable
✅ Efficient
✅ Tamper-proof

It’s perfect for APIs with infinite scrolling, real-time updates, or frequent insertions/deletions.


How CursorPagination Works

  • Each response includes a next and previous link with a cursor value.

  • The cursor is a base64-encoded reference to the current position in the result set.

  • It uses an ordering field (e.g., created_at, id) to navigate through the records.


Example API Response

{
  "next": "http://localhost:8000/api/posts/?cursor=cD0yMDI0LTEwLTI4...",
  "previous": null,
  "results": [
    {
      "id": 1,
      "title": "Latest Post",
      "created_at": "2024-10-28T10:00:00Z"
    },
    ...
  ]
}

Implementing CursorPagination

Step 1: Define the Pagination Class

# pagination.py
from rest_framework.pagination import CursorPagination

class CustomCursorPagination(CursorPagination):
    page_size = 5
    ordering = '-created_at'  # Required: determines navigation order

Step 2: Apply It Globally (optional)

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'yourapp.pagination.CustomCursorPagination',
    'PAGE_SIZE': 5,
}

Step 3: Use It in a View or ViewSet

# views.py
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
from .pagination import CustomCursorPagination

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    pagination_class = CustomCursorPagination  # Optional if set globally

Step 4: Ensure You Have a Proper Ordering Field

You must have a unique, ordered field—like created_at, updated_at, or id.

# models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

✅ Full Working Example

serializers.py

from rest_framework import serializers
from .models import Post

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

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)),
]

When Should You Use CursorPagination?

Use it when:

  • You need stable pagination despite frequent data changes

  • You want secure cursors (can’t be manipulated like ?offset=9999)

  • You’re implementing infinite scroll or "load more" buttons

  • You want better performance at scale


✅ Tips & Best Practices

Tip Why It Matters
✅ Use a unique, indexed field for ordering Ensures stable and performant pagination
✅ Use descending order (-created_at) Shows latest records first
✅ Set a page_size Keeps results manageable
✅ Always expose next and previous Enables full navigation
✅ Use in infinite scroll UIs Cursor-based APIs pair well with frontend load-more logic

⚠️ Common Pitfalls

Pitfall Fix
❌ Using non-unique fields for ordering Can result in incorrect or duplicate records
❌ Not including an ordering field DRF will raise an error
❌ Clients manually editing cursors Always treat cursors as opaque values
❌ Expecting page numbers CursorPagination does not support traditional page numbers
❌ Using it with filters without stable ordering Combine filtering with stable ordering to avoid unexpected results

Comparison with Other Pagination Classes

Feature PageNumberPagination LimitOffsetPagination CursorPagination
Simple to use ❌ Slightly complex
Stable under data changes
Supports infinite scroll ⚠️ Limited ✅ Best
Exposes total count ❌ No count
Query tamper-proof
Fast at scale

Conclusion

CursorPagination is a robust, secure, and high-performance pagination solution for APIs. It’s ideal for large datasets and dynamic applications where content is constantly updated.

If you’re building:

  • A mobile app feed

  • A social media timeline

  • An infinite scroll UI

  • A highly dynamic API

...then CursorPagination is your best choice.