Add LinkPagination support

This commit is contained in:
David Medina 2013-10-10 11:16:28 +02:00
parent a500b83ff2
commit bf227649f4
2 changed files with 60 additions and 1 deletions

View File

@ -10,6 +10,7 @@ from django.http import Http404
from rest_framework import status from rest_framework import status
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.request import clone_request from rest_framework.request import clone_request
from rest_framework import pagination
import warnings import warnings
@ -187,3 +188,15 @@ class DestroyModelMixin(object):
obj = self.get_object() obj = self.get_object()
obj.delete() obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
class LinkPaginationMixin(object):
pagination_serializer_class = pagination.LinkPaginationSerializer
def paginate_queryset(self, queryset, page_size=None):
page = super(LinkPaginationMixin, self).paginate_queryset(
queryset, page_size)
if page:
page_ser = self.get_pagination_serializer(page)
self.headers.update(page_ser.get_link_header())
return None # Don't use pagination serializer on response

View File

@ -49,6 +49,35 @@ class PreviousPageField(serializers.Field):
return replace_query_param(url, self.page_field, page) return replace_query_param(url, self.page_field, page)
class FirstPageField(serializers.Field):
"""
Field that returns a link to the first page in paginated results.
"""
page_field = 'page'
def to_native(self, value):
if not value.has_previous():
return None
request = self.context.get('request')
url = request and request.build_absolute_uri() or ''
return replace_query_param(url, self.page_field, 1)
class LastPageField(serializers.Field):
"""
Field that returns a link to the previous page in paginated results.
"""
page_field = 'page'
def to_native(self, value):
if not value.has_next():
return None
page = value.paginator.num_pages
request = self.context.get('request')
url = request and request.build_absolute_uri() or ''
return replace_query_param(url, self.page_field, page)
class DefaultObjectSerializer(serializers.Field): class DefaultObjectSerializer(serializers.Field):
""" """
If no object serializer is specified, then this serializer will be applied If no object serializer is specified, then this serializer will be applied
@ -94,7 +123,8 @@ class BasePaginationSerializer(serializers.Serializer):
else: else:
context_kwarg = {} context_kwarg = {}
self.fields[results_field] = object_serializer(source='object_list', **context_kwarg) self.fields[results_field] = object_serializer(source='object_list',
**context_kwarg)
class PaginationSerializer(BasePaginationSerializer): class PaginationSerializer(BasePaginationSerializer):
@ -104,3 +134,19 @@ class PaginationSerializer(BasePaginationSerializer):
count = serializers.Field(source='paginator.count') count = serializers.Field(source='paginator.count')
next = NextPageField(source='*') next = NextPageField(source='*')
previous = PreviousPageField(source='*') previous = PreviousPageField(source='*')
class LinkPaginationSerializer(PaginationSerializer):
""" Pagination serializer in order to build Link header """
first = FirstPageField(source='*')
last = LastPageField(source='*')
relations = ('next', 'previous', 'first', 'last')
def get_link_header(self):
link_keader_items = [
'<%s>; rel="%s"' % (link, rel)
for rel, link in self.data.items()
if (rel in self.relations and link is not None)
]
return {'Link': ', '.join(link_keader_items)}