I'm currently trying to create an API that return list of objects with page and limit per page input from url parameter using django-rest-framework which i already done in my api view with custom Pagination
class PropertyListPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
def get_paginated_response(self, data):
return Response({
'code': 200,
'data': data
})
@api_view(['GET'])
def property_list(request):
if request.method == 'GET':
paginator = PropertyListPagination()
queryset = Property.objects.all()
context = paginator.paginate_queryset(queryset, request)
serializer = PropertySerializer(context, many=True)
return paginator.get_paginated_response(serializer.data)
Currently if a page is out of range( for example if i have only 2 object and i set my url to page=3 and page_size=1 then it should out of range of total objects) then in the response it will return a 404 status and in the body:
{
"detail": "Invalid page."
}
Is there a way to customize for it to return 400 status and the following json body ?
{
"code": 400,
"error": "Page out of range"
}
Thank you
You can achieve it by overriding NotFound
class and thenpaginate_queryset
method,
from rest_framework.exceptions import NotFound
from rest_framework.exceptions import APIException
class NotFound(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = ('bad_request.')
default_code = 'bad_request'
class PropertyListPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
def paginate_queryset(self, queryset, request, view=None):
"""
Paginate a queryset if required, either returning a
page object, or `None` if pagination is not configured for this view.
"""
page_size = self.get_page_size(request)
if not page_size:
return None
paginator = self.django_paginator_class(queryset, page_size)
page_number = request.query_params.get(self.page_query_param, 1)
if page_number in self.last_page_strings:
page_number = paginator.num_pages
try:
self.page = paginator.page(page_number)
except Exception as exc:
# Here it is
msg = {
"code": 400 # you can remove this line as now the status code will be 400 by default as we have override it in `NotFound` class(see above)
"error": "Page out of range"
}
raise NotFound(msg)
if paginator.num_pages > 1 and self.template is not None:
# The browsable API should display pagination controls.
self.display_page_controls = True
self.request = request
return list(self.page)