Cleaning up cursor implementation

This commit is contained in:
Tom Christie 2015-01-17 00:59:02 +00:00
parent 4919492582
commit 492f3c410d

View File

@ -381,10 +381,33 @@ class LimitOffsetPagination(BasePagination):
return template.render(context) return template.render(context)
Cursor = namedtuple('Cursor', ['offset', 'reverse', 'position'])
def decode_cursor(encoded):
tokens = urlparse.parse_qs(b64decode(encoded))
try:
offset = int(tokens['offset'][0])
reverse = bool(int(tokens['reverse'][0]))
position = tokens['position'][0]
except (TypeError, ValueError):
return None
return Cursor(offset=offset, reverse=reverse, position=position)
def encode_cursor(cursor):
tokens = {
'offset': str(cursor.offset),
'reverse': '1' if cursor.reverse else '0',
'position': cursor.position
}
return b64encode(urlparse.urlencode(tokens, doseq=True))
class CursorPagination(BasePagination): class CursorPagination(BasePagination):
# reverse # reverse
# limit # limit
# multiple orderings
cursor_query_param = 'cursor' cursor_query_param = 'cursor'
page_size = 5 page_size = 5
@ -396,10 +419,11 @@ class CursorPagination(BasePagination):
if encoded is None: if encoded is None:
cursor = None cursor = None
else: else:
cursor = self.decode_cursor(encoded, self.ordering) cursor = decode_cursor(encoded)
# TODO: Invalid cursors should 404
if cursor is not None: if cursor is not None:
kwargs = {self.ordering + '__gt': cursor} kwargs = {self.ordering + '__gt': cursor.position}
queryset = queryset.filter(**kwargs) queryset = queryset.filter(**kwargs)
results = list(queryset[:self.page_size + 1]) results = list(queryset[:self.page_size + 1])
@ -411,20 +435,21 @@ class CursorPagination(BasePagination):
if not self.has_next: if not self.has_next:
return None return None
last_item = self.page[-1] last_item = self.page[-1]
cursor = self.get_cursor_from_instance(last_item, self.ordering) position = self.get_position_from_instance(last_item, self.ordering)
encoded = self.encode_cursor(cursor, self.ordering) cursor = Cursor(offset=0, reverse=False, position=position)
encoded = encode_cursor(cursor)
return replace_query_param(self.base_url, self.cursor_query_param, encoded) return replace_query_param(self.base_url, self.cursor_query_param, encoded)
def get_ordering(self): def get_ordering(self):
return 'created' return 'created'
def get_cursor_from_instance(self, instance, ordering): def get_position_from_instance(self, instance, ordering):
return getattr(instance, ordering) return str(getattr(instance, ordering))
def decode_cursor(self, encoded, ordering): # def decode_cursor(self, encoded, ordering):
items = urlparse.parse_qs(b64decode(encoded)) # items = urlparse.parse_qs(b64decode(encoded))
return items.get(ordering)[0] # return items.get(ordering)[0]
def encode_cursor(self, cursor, ordering): # def encode_cursor(self, cursor, ordering):
items = [(ordering, cursor)] # items = [(ordering, cursor)]
return b64encode(urlparse.urlencode(items, doseq=True)) # return b64encode(urlparse.urlencode(items, doseq=True))