text: from django.core.paginator import EmptyPage, InvalidPage
  
  
  def get_page(queryset, order_by, per_page, start=0):
      if start < 0:
          raise InvalidPage()
  
      object_list = list(_slice_queryset(queryset, order_by, per_page, start))
      if start and not object_list:
          raise EmptyPage()
  
      next_cursor = None
      if len(object_list) > per_page:
          next_slice_first_item = object_list.pop(-1)
          attr_name = order_by.lstrip("-")
          next_cursor = getattr(next_slice_first_item, attr_name)
  
      return CursorPage(start, object_list, next_cursor)
  
  
  def _slice_queryset(queryset, order_by, per_page, start):
      page_len = int(per_page) + 1
      if start:
          if order_by.startswith("-"):
              filter_name = "%s__lte" % order_by[1:]
          else:
              filter_name = "%s__gte" % order_by
          return queryset.filter(**{filter_name: start})[:page_len]
      return queryset[:page_len]
  
  
  class CursorPage:
      def __init__(self, start, object_list, next_=None):
          self.start = start or 0
          self.first = self.start == 0
          self.object_list = object_list
          self.next = next_
  
      def __len__(self):
          return len(self.object_list)
  
      def has_next(self):
          return bool(self.next)
  