apipaginator.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. from django.core.paginator import InvalidPage, Paginator as DjangoPaginator
  2. from rest_framework.compat import OrderedDict
  3. from rest_framework.exceptions import NotFound
  4. from rest_framework.pagination import PageNumberPagination
  5. from rest_framework.response import Response
  6. class BaseApiPaginator(PageNumberPagination):
  7. def paginate_queryset(self, queryset, request, view=None):
  8. """
  9. Paginate a queryset if required, either returning a
  10. page object, or `None` if pagination is not configured for this view.
  11. """
  12. paginator = DjangoPaginator(
  13. queryset, self.page_size, orphans=self.page_orphans)
  14. page_number = request.query_params.get(self.page_query_param, 1)
  15. try:
  16. self.page = paginator.page(page_number)
  17. except InvalidPage as exc:
  18. msg = self.invalid_page_message.format(
  19. page_number=page_number, message=six.text_type(exc)
  20. )
  21. raise NotFound(msg)
  22. if paginator.count > 1 and self.template is not None:
  23. # The browsable API should display pagination controls.
  24. self.display_page_controls = True
  25. self.request = request
  26. return list(self.page)
  27. def get_meta(self):
  28. pagination = {
  29. 'pages': self.page.paginator.num_pages,
  30. 'first': None,
  31. 'previous': None,
  32. 'next': None,
  33. 'last': None,
  34. }
  35. if self.page.has_previous():
  36. pagination['first'] = 1
  37. if self.page.previous_page_number() > 1:
  38. pagination['previous'] = self.page.previous_page_number()
  39. if self.page.has_next():
  40. pagination['last'] = self.page.paginator.num_pages
  41. if self.page.next_page_number() < self.page.paginator.num_pages:
  42. pagination['next'] = self.page.next_page_number()
  43. return OrderedDict([
  44. ('count', self.page.paginator.count),
  45. ('pages', pagination['pages']),
  46. ('first', pagination['first']),
  47. ('previous', pagination['previous']),
  48. ('next', pagination['next']),
  49. ('last', pagination['last'])
  50. ])
  51. def get_paginated_response(self, data):
  52. response_data = self.get_meta()
  53. response_data['results'] = data
  54. return Response(response_data)
  55. def ApiPaginator(per_page=None, orphans=0):
  56. return type('ApiPaginator', (BaseApiPaginator, ), {
  57. 'page_size': per_page,
  58. 'page_orphans': orphans
  59. })