'Django PageNumberPagination customize error if page number out of range
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
Solution 1:[1]
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)
Solution 2:[2]
You can simply, wrap the pagination code in try-except, this is just a temporary solution I found.
Expect block will be executed instead of {"detail": "Invalid page."} message
try :
context = paginator.paginate_queryset(filteredData, request)
serializer = AuthUserSerializer(context,many=True)
return Response(serializer.data)
except:
# return here any message you want
return Response({
"code": 400,
"error": "Page out of range"
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Rushi Creates |