1234567891011121314151617181920212223242526272829303132333435363738394041424344 |
- 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)
|