123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 |
- from rest_framework import status
- from rest_framework.pagination import CursorPagination
- from rest_framework.response import Response
- from rest_framework.utils.urls import replace_query_param
- class LinkHeaderCursorPagination(CursorPagination):
- """
- Inform the user of pagination links via response headers, similar to what's
- described in https://developer.github.com/v3/guides/traversing-with-pagination/
- Inspired by the django-rest-framework-link-header-pagination package.
- """
- template = None
- @staticmethod
- def construct_headers(pagination_map):
- links = [
- f'<{url}>; rel="{label}"'
- for label, url in pagination_map.items()
- if url is not None
- ]
- return {"Link": ", ".join(links)} if links else {}
- def get_paginated_response(self, data):
- pagination_required = self.has_next or self.has_previous
- if not pagination_required:
- return Response(data)
- url = self.request.build_absolute_uri()
- pagination_map = {
- "first": replace_query_param(url, self.cursor_query_param, "")
- }
- if self.cursor_query_param not in self.request.query_params:
- count = self.queryset.count()
- data = {
- "detail": f"Pagination required. You can query up to {self.page_size} items at a time ({count} total). "
- "Please use the `first` page link (see Link header).",
- }
- headers = self.construct_headers(pagination_map)
- return Response(data, headers=headers, status=status.HTTP_400_BAD_REQUEST)
- pagination_map.update(prev=self.get_previous_link(), next=self.get_next_link())
- headers = self.construct_headers(pagination_map)
- return Response(data, headers=headers)
- def paginate_queryset(self, queryset, request, view=None):
- self.request = request
- self.queryset = queryset
- return super().paginate_queryset(queryset, request, view)
|