apipaginator.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. 'before': 0,
  35. 'more': 0,
  36. }
  37. if self.page.has_previous():
  38. pagination['first'] = 1
  39. if self.page.previous_page_number() > 1:
  40. pagination['previous'] = self.page.previous_page_number()
  41. if self.page.has_next():
  42. pagination['last'] = self.page.paginator.num_pages
  43. if self.page.next_page_number() < self.page.paginator.num_pages:
  44. pagination['next'] = self.page.next_page_number()
  45. if self.page.start_index():
  46. pagination['before'] = self.page.start_index() - 1
  47. pagination['more'] = self.page.paginator.count - self.page.end_index()
  48. return OrderedDict([
  49. ('count', self.page.paginator.count),
  50. ('pages', pagination['pages']),
  51. ('first', pagination['first']),
  52. ('previous', pagination['previous']),
  53. ('next', pagination['next']),
  54. ('last', pagination['last']),
  55. ('before', pagination['before']),
  56. ('more', pagination['more'])
  57. ])
  58. def get_paginated_response(self, data):
  59. response_data = self.get_meta()
  60. response_data['results'] = data
  61. return Response(response_data)
  62. def ApiPaginator(per_page=None, orphans=0):
  63. return type('ApiPaginator', (BaseApiPaginator, ), {
  64. 'page_size': per_page,
  65. 'page_orphans': orphans
  66. })