When building APIs, it's important to manage large datasets efficiently. Django Rest Framework (DRF) provides several pagination strategies — one of the most flexible being LimitOffsetPagination
.
This article covers:
-
What
LimitOffsetPagination
is -
How it works
-
How to configure and use it
-
Code example
-
Tips and common pitfalls
What is LimitOffsetPagination
?
LimitOffsetPagination
allows clients to specify:
-
How many items they want (
limit
) -
Where to start in the dataset (
offset
)
This gives the client more control over how they retrieve data compared to PageNumberPagination
.
Example URL:
GET /api/posts/?limit=10&offset=20
→ Retrieves 10 posts starting from the 21st record.
⚙️ How it Works
DRF intercepts requests to views using LimitOffsetPagination
and applies the requested limit
and offset
to the queryset. The response includes pagination metadata and the sliced results.
Default Behavior:
Parameter | Default |
---|---|
limit |
DEFAULT_LIMIT (10 if not set) |
offset |
0 (starts at the beginning) |
Setting Up LimitOffsetPagination
Step 1: Set it Globally (Optional)
In settings.py
:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10, # used as default limit
}
You can also override the pagination class per-view.
Step 2: Define a Custom Pagination Class (Optional)
# pagination.py
from rest_framework.pagination import LimitOffsetPagination
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5
max_limit = 50
Step 3: Use it in a View
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
from .pagination import CustomLimitOffsetPagination
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
pagination_class = CustomLimitOffsetPagination
✅ Example Response
{
"count": 125,
"next": "http://localhost:8000/api/posts/?limit=5&offset=10",
"previous": "http://localhost:8000/api/posts/?limit=5&offset=0",
"results": [
{
"id": 11,
"title": "Post 11",
"content": "..."
},
...
]
}
✅ Complete Code 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 LimitOffsetPagination
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5
max_limit = 100
views.py
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
from .pagination import CustomLimitOffsetPagination
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
pagination_class = CustomLimitOffsetPagination
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 max_limit |
Prevents abuse by large data requests |
✅ Combine with caching | Avoids reprocessing identical queries |
✅ Use count field to show total available records |
|
✅ Use in infinite scroll UIs | Easier to manage than page-based pagination |
⚠️ Common Pitfalls
Pitfall | Fix |
---|---|
❌ Missing limit parameter returns default only |
Set PAGE_SIZE or default_limit to control behavior |
❌ Exposing entire dataset by setting huge limit | Always use max_limit |
❌ Using in views without pagination_class |
Pagination won’t be applied |
❌ Relying on offset for frequently-changing data | Use CursorPagination for stable pagination in such cases |
PageNumberPagination
vs LimitOffsetPagination
Feature | PageNumberPagination |
LimitOffsetPagination |
---|---|---|
Simple | ✅ Yes | ❌ Slightly more complex |
Infinite Scroll Friendly | ❌ No | ✅ Yes |
Control over data size | ❌ No | ✅ Yes |
Ideal for user interfaces with page numbers | ✅ Yes | ❌ Not ideal |
Conclusion
LimitOffsetPagination
provides flexibility and fine-grained control to clients when interacting with large datasets. It's ideal for APIs consumed by JavaScript frontends and mobile apps, especially where infinite scrolling or dynamic loading is needed.
If you need a more secure and stable pagination for large, changing datasets, check out CursorPagination
next.