cursorpagination.py 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. from django.core.paginator import EmptyPage, InvalidPage
  2. def get_page(queryset, order_by, per_page, start=0):
  3. if start < 0:
  4. raise InvalidPage()
  5. object_list = list(_slice_queryset(queryset, order_by, per_page, start))
  6. if start and not object_list:
  7. raise EmptyPage()
  8. next_cursor = None
  9. if len(object_list) > per_page:
  10. next_slice_first_item = object_list.pop(-1)
  11. attr_name = order_by.lstrip("-")
  12. next_cursor = getattr(next_slice_first_item, attr_name)
  13. return CursorPage(start, object_list, next_cursor)
  14. def _slice_queryset(queryset, order_by, per_page, start):
  15. page_len = int(per_page) + 1
  16. if start:
  17. if order_by.startswith("-"):
  18. filter_name = "%s__lte" % order_by[1:]
  19. else:
  20. filter_name = "%s__gte" % order_by
  21. return queryset.filter(**{filter_name: start})[:page_len]
  22. return queryset[:page_len]
  23. class CursorPage:
  24. def __init__(self, start, object_list, next_=None):
  25. self.start = start or 0
  26. self.first = self.start == 0
  27. self.object_list = object_list
  28. self.next = next_
  29. def __len__(self):
  30. return len(self.object_list)
  31. def has_next(self):
  32. return bool(self.next)