|
1 | 1 | from collections import OrderedDict
|
| 2 | +from urllib.parse import parse_qs, urlparse |
2 | 3 |
|
3 | 4 | from rest_framework.pagination import LimitOffsetPagination as _LimitOffsetPagination
|
| 5 | +from rest_framework.pagination import CursorPagination as _CursorPagination |
4 | 6 | from rest_framework.response import Response
|
5 | 7 |
|
6 | 8 |
|
@@ -45,3 +47,48 @@ def get_paginated_response(self, data):
|
45 | 47 | ('previous', self.get_previous_link()),
|
46 | 48 | ('results', data)
|
47 | 49 | ]))
|
| 50 | + |
| 51 | + |
| 52 | +class CursorPagination(_CursorPagination): |
| 53 | + page_size = 50 # Return 50 items by default |
| 54 | + |
| 55 | + def __init__(self, ordering): |
| 56 | + self.ordering: str = ordering or "-created_at" |
| 57 | + |
| 58 | + def get_ordering(self, request, queryset, view): |
| 59 | + # The DRF CursorPagination expects the ordering as a tuple |
| 60 | + if isinstance(self.ordering, str): |
| 61 | + return (self.ordering,) |
| 62 | + |
| 63 | + return tuple(self.ordering) |
| 64 | + |
| 65 | + def _get_cursor(self, url): |
| 66 | + if not url: |
| 67 | + return None |
| 68 | + |
| 69 | + parsed_params = parse_qs(urlparse(url).query) |
| 70 | + # `parse_qs` values are lists |
| 71 | + cursor_params = parsed_params.get("cursor", []) |
| 72 | + if not cursor_params: |
| 73 | + return None |
| 74 | + |
| 75 | + return cursor_params[0] |
| 76 | + |
| 77 | + def get_paginated_response(self, data): |
| 78 | + next_url = self.get_next_link() |
| 79 | + next_cursor = self._get_cursor(next_url) |
| 80 | + |
| 81 | + previous_url = self.get_previous_link() |
| 82 | + previous_cursor = self._get_cursor(previous_url) |
| 83 | + |
| 84 | + return Response( |
| 85 | + OrderedDict( |
| 86 | + [ |
| 87 | + ("next", next_url), |
| 88 | + ("next_cursor", next_cursor), |
| 89 | + ("previous", previous_url), |
| 90 | + ("previous_cursor", previous_cursor), |
| 91 | + ("results", data), |
| 92 | + ] |
| 93 | + ) |
| 94 | + ) |
0 commit comments