Django REST Framework `pagination_class` on ViewSet is ignored
Describe the Problem
I have a ModelViewSet
in Django REST Framework designed to return a list of Order
objects. To improve performance, I'm trying to implement custom pagination that limits the results to 65 per page.
Despite setting the pagination_class
property directly on my ViewSet
, the API endpoint continues to return the full, unpaginated queryset (over 300 objects). It seems my custom pagination class is being completely ignored.
My goal is for the API to return a paginated response with a count
, next
, previous
, and a results
list containing a maximum of 65 items when I request .../api/orders/?page=1
.
What I Tried
Here is my setup:
1. pagination.py
: I created a custom pagination class.
# my_app/pagination.py
from rest_framework.pagination import PageNumberPagination
class CustomOrderPagination(PageNumberPagination):
page_size = 65
page_size_query_param = 'page_size'
max_page_size = 100
2. views.py
: I assigned this custom class to my ViewSet
. The queryset uses select_related
and prefetch_related
for performance.
# my_app/views.py
from rest_framework import viewsets
from django.db.models import Sum
from .models import Order
from .serializers import OrderSlimSerializer
from .pagination import CustomOrderPagination
class OrderViewSet(viewsets.ModelViewSet):
# I explicitly set the pagination class here
pagination_class = CustomOrderPagination
serializer_class = OrderSlimSerializer
queryset = Order.objects.select_related('client').prefetch_related(
'orderitem_set__location__service_plan'
).annotate(
total_amount=Sum('orderitem_set__service_plan__service_fee')
)
# ... (permission_classes, filter_backends, etc.) ...
3. serializers.py
: I'm using optimized "slim" serializers to keep the payload small.
# my_app/serializers.py
class LocationItemSerializer(serializers.ModelSerializer):
# ... returns a small payload for each location ...
class Meta:
model = OrderItem
fields = ['location_name', 'service_plan_details']
class OrderSlimSerializer(serializers.ModelSerializer):
client_name = serializers.CharField(source='client.name')
locations = LocationItemSerializer(source='orderitem_set', many=True)
charge_amount = serializers.DecimalField(source='total_amount', read_only=True)
class Meta:
model = Order
fields = ['id', 'order_number', 'client_name', 'locations', 'charge_amount']
4. The Request: I am making the request correctly with the page
parameter.
curl "http://localhost:8000/api/orders/?page=1"
5. Pagination is Configured in Settings.py:
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 100,
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
}
The Result: The response is a single list of all 300+ Order
objects, not a paginated dictionary like {"count": 368, "next": ..., "results": [...]}
.
Question: Why is my pagination_class
setting being ignored on the OrderViewSet
, and what is the correct way to ensure this custom pagination is applied? Is there a global setting I might be missing that disables pagination entirely?
PS: I also checked out this question, but since it’s about plain
ViewSet
, notModelViewSet
, I wasn’t sure how to adapt it to my case.
Thanks for the replies!
Turns out the issue was on my side — I had defined CustomOrderPagination
in a separate pagination.py
file but was importing it from a different module that wasn’t actually being used by the ViewSet
.
To debug, I added:
def paginate_queryset(self, queryset):
print("called paginate_queryset")
return super().paginate_queryset(queryset)
But nothing was printed — and that’s when I realized I was assigning a pagination class that wasn't even getting loaded. Once I fixed the import and confirmed the correct pagination class was being used, everything started working as expected.
Appreciate your help — especially the suggestion to override paginate_queryset()
, that helped me track it down 🙌
One of those “it works in one tab, but not in the one you’re testing” moments 😅 Thanks again!