cursorpaginator.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. from django.core.paginator import EmptyPage, InvalidPage
  2. class CursorPaginator:
  3. def __init__(self, queryset, order_by, per_page):
  4. self.queryset = queryset
  5. self.per_page = int(per_page)
  6. if order_by.startswith("-"):
  7. self.order_by = order_by[1:]
  8. self.desc = True
  9. else:
  10. self.order_by = order_by
  11. self.desc = False
  12. def get_page(self, start=0):
  13. if start < 0:
  14. raise InvalidPage()
  15. object_list = list(self._get_slice(start))
  16. if start and not object_list:
  17. raise EmptyPage()
  18. next_cursor = None
  19. if len(object_list) > self.per_page:
  20. next_slice_first_item = object_list.pop(-1)
  21. next_cursor = getattr(next_slice_first_item, self.order_by)
  22. return Page(start, object_list, next_cursor)
  23. def _get_slice(self, start):
  24. page_len = self.per_page + 1
  25. if start:
  26. print(start)
  27. if self.desc:
  28. filter_name = "%s__lte" % self.order_by
  29. else:
  30. filter_name = "%s__gte" % self.order_by
  31. print({filter_name: start})
  32. return self.queryset.filter(**{filter_name: start})[:page_len]
  33. return self.queryset[:page_len]
  34. class Page:
  35. def __init__(self, start, object_list, next_):
  36. self.start = start or 0
  37. self.object_list = object_list
  38. self.next = next_
  39. def __len__(self):
  40. return len(self.object_list)
  41. def has_next(self):
  42. return bool(self.next)