Given the high-volume, time-based nature of this API, cursor-based pagination provides some important usability improvements over page number-based pagination, most notably in going back through historical pages.
Signed-off-by: Stephen Finucane <step...@that.guru> Cc: Aaron Conole <acon...@bytheb.org> --- patchwork/api/base.py | 30 +++++++++++++++++++++++------- patchwork/api/event.py | 4 +++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/patchwork/api/base.py b/patchwork/api/base.py index 09b3bef..958dfc3 100644 --- a/patchwork/api/base.py +++ b/patchwork/api/base.py @@ -19,22 +19,20 @@ from django.conf import settings from django.shortcuts import get_object_or_404 +from rest_framework import pagination from rest_framework import permissions -from rest_framework.pagination import PageNumberPagination from rest_framework.response import Response from rest_framework.serializers import HyperlinkedIdentityField -class LinkHeaderPagination(PageNumberPagination): - """Provide pagination based on rfc5988. +class LinkHeaderMixin(object): + """Provide pagination based on RFC5988. This is the Link header, similar to how GitHub does it. See: - https://tools.ietf.org/html/rfc5988#section-5 - https://developer.github.com/guides/traversing-with-pagination + - https://tools.ietf.org/html/rfc5988#section-5 + - https://developer.github.com/guides/traversing-with-pagination """ - page_size = max_page_size = settings.REST_RESULTS_PER_PAGE - page_size_query_param = 'per_page' def get_paginated_response(self, data): next_url = self.get_next_link() @@ -47,11 +45,29 @@ class LinkHeaderPagination(PageNumberPagination): link = '<{next_url}>; rel="next"' elif previous_url is not None: link = '<{previous_url}>; rel="prev"' + link = link.format(next_url=next_url, previous_url=previous_url) headers = {'Link': link} if link else {} + return Response(data, headers=headers) + +class PageNumberPagination(LinkHeaderMixin, pagination.PageNumberPagination): + """RFC5988-based page-number pagination.""" + page_size = max_page_size = settings.REST_RESULTS_PER_PAGE + page_size_query_param = 'per_page' + + +class CursorPagination(LinkHeaderMixin, pagination.CursorPagination): + """RFC5988-based cursor pagination.""" + page_size = 30 + cursor_query_param = 'cursor' + + +LinkHeaderPagination = PageNumberPagination + + class PatchworkPermission(permissions.BasePermission): """This permission works for Project and Patch model objects""" def has_object_permission(self, request, view, obj): diff --git a/patchwork/api/event.py b/patchwork/api/event.py index cc9270a..d333501 100644 --- a/patchwork/api/event.py +++ b/patchwork/api/event.py @@ -23,6 +23,7 @@ from rest_framework.generics import ListAPIView from rest_framework.serializers import ModelSerializer from rest_framework.serializers import SerializerMethodField +from patchwork.api.base import CursorPagination from patchwork.api.embedded import CheckSerializer from patchwork.api.embedded import CoverLetterSerializer from patchwork.api.embedded import PatchSerializer @@ -34,6 +35,7 @@ from patchwork.api.patch import StateField from patchwork.models import Event + class EventSerializer(ModelSerializer): project = ProjectSerializer(read_only=True) @@ -89,8 +91,8 @@ class EventList(ListAPIView): """List events.""" serializer_class = EventSerializer + pagination_class = CursorPagination filter_class = EventFilter - page_size_query_param = None # fixed page size ordering = '-date' ordering_fields = () -- 2.9.4 _______________________________________________ Patchwork mailing list Patchwork@lists.ozlabs.org https://lists.ozlabs.org/listinfo/patchwork