api/webview/pagination.py
import six
from collections import OrderedDict
from django.core.paginator import Paginator as DjangoPaginator
from django.core.paginator import InvalidPage, PageNotAnInteger, EmptyPage
from rest_framework.response import Response
from rest_framework.exceptions import NotFound
from rest_framework.utils.urls import replace_query_param
from rest_framework.pagination import PageNumberPagination
class PageNumberPaginationWithoutCount(PageNumberPagination):
# Set any other options you want here like page_size
def get_paginated_response(self, data):
return Response(OrderedDict([
('next', self.get_next_link() if data else None),
('previous', self.get_previous_link()),
('results', data)
]))
def get_next_link(self):
url = self.request.build_absolute_uri()
page_number = self.page.next_page_number()
return replace_query_param(url, self.page_query_param, page_number)
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 = PaginatorWithoutCount(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 InvalidPage as exc:
msg = self.invalid_page_message.format(
page_number=page_number, message=six.text_type(exc)
)
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)
class PaginatorWithoutCount(DjangoPaginator):
def __init__(self, *args, **kwargs):
super(PaginatorWithoutCount, self).__init__(*args, **kwargs)
self._count = 0
def page(self, number):
number = self.validate_number(number)
bottom = (number - 1) * self.per_page
top = bottom + self.per_page
return self._get_page(self.object_list[bottom:top], number, self)
def validate_number(self, number):
try:
number = int(number)
except (TypeError, ValueError):
raise PageNotAnInteger('That page number is not an integer')
if number < 1:
raise EmptyPage('That page number is less than 1')
return number