pagination.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import urllib.parse as urlparse
  2. from urllib.parse import parse_qs
  3. from rest_framework.pagination import CursorPagination
  4. from rest_framework.response import Response
  5. class LinkHeaderPagination(CursorPagination):
  6. """ Inform the user of pagination links via response headers, similar to
  7. what's described in
  8. https://developer.github.com/guides/traversing-with-pagination/.
  9. """
  10. page_size_query_param = "limit"
  11. max_hits = 1000
  12. def paginate_queryset(self, queryset, request, view=None):
  13. self.count = self.get_count(queryset)
  14. return super().paginate_queryset(queryset, request, view)
  15. def get_count(self, queryset):
  16. """ Count with max limit, to prevent slowdown """
  17. return queryset[: self.max_hits].count()
  18. def get_paginated_response(self, data):
  19. next_url = self.get_next_link()
  20. previous_url = self.get_previous_link()
  21. links = []
  22. for url, label in (
  23. (previous_url, "previous"),
  24. (next_url, "next"),
  25. ):
  26. if url is not None:
  27. parsed = urlparse.urlparse(url)
  28. cursor = parse_qs(parsed.query).get(self.cursor_query_param, [""])[0]
  29. links.append(
  30. '<{}>; rel="{}"; results="true"; cursor="{}"'.format(
  31. url, label, cursor
  32. )
  33. )
  34. else:
  35. links.append(
  36. '<{}>; rel="{}"; results="false"'.format(self.base_url, label)
  37. )
  38. headers = {"Link": ", ".join(links)} if links else {}
  39. headers["X-Max-Hits"] = self.max_hits
  40. headers["X-Hits"] = self.count
  41. return Response(data, headers=headers)