Source code for restae.pagination
"""
Paginator working with datastore
"""
from collections import OrderedDict
from google.appengine.api.datastore_errors import BadValueError
from google.appengine.ext.ndb import Cursor
from restae.response import JsonResponse
from restae.conf import settings, DEFAULT_PAGE_SIZE
from restae.exceptions import InvalidPage, NotFound, BadRequest
[docs]class BasePagination(object):
display_page_controls = False
def paginate_queryset(self, queryset, request, view=None):
raise NotImplementedError('paginate_queryset() must be implemented.')
def get_paginated_response(self, data): # pragma: no cover
raise NotImplementedError('get_paginated_response() must be implemented.')
def get_results(self, data):
return data['results']
def get_page_size(self, request):
return int(request.GET.get('page_size', settings.get('PAGE_SIZE', DEFAULT_PAGE_SIZE)))
[docs]class CursorPagination(BasePagination):
"""
A simple cursor based style that supports cursors urlsafe as
query parameters. For example:
http://api.example.org/accounts/?page_token=<URLSAFE STRING>
"""
def __init__(self):
self.count = 0
self.page = None
self.next_page = None
self.has_next = None
self.request = None
def get_page_token(self):
return self.request.GET.get('page_token', None)
[docs] def paginate_queryset(self, queryset, request, view=None):
"""
Paginate a queryset if required, either returning a
page object, or `None` if pagination is not configured for this view.
"""
self.count = queryset.count()
self.request = request
try:
self.page, self.next_page, self.has_next = queryset.fetch_page(
self.get_page_size(request), start_cursor=Cursor(urlsafe=self.get_page_token()))
except InvalidPage:
raise NotFound('Requested page not found')
except BadValueError as err:
raise BadRequest(str(err))
return list(self.page)
def get_paginated_response(self, data):
return JsonResponse(data=OrderedDict([
('count', self.count),
('next', self.get_next_link()),
# ('previous', self.get_previous_link()),
('results', data)
]))
def get_next_link(self):
if not self.has_next:
return None
return self.next_page.urlsafe()
# def get_previous_link(self):
# if self.next_page is not None and self.get_page_token() is not None:
# return self.next_page.reversed().urlsafe()
# return None