mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-29 13:04:03 +03:00
Added pagination mixin. Need to write tests
This commit is contained in:
parent
a53101bea9
commit
1eb2dfcc3a
|
@ -4,6 +4,7 @@ classes that can be added to a `View`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.core.paginator import Paginator
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.db.models.fields.related import ForeignKey
|
from django.db.models.fields.related import ForeignKey
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
@ -637,4 +638,92 @@ class ListModelMixin(object):
|
||||||
queryset = queryset.order_by(*args)
|
queryset = queryset.order_by(*args)
|
||||||
return queryset.filter(**kwargs)
|
return queryset.filter(**kwargs)
|
||||||
|
|
||||||
|
########## Pagination Mixins ##########
|
||||||
|
|
||||||
|
class PaginatorMixin(object):
|
||||||
|
"""
|
||||||
|
Adds pagination support to GET requests
|
||||||
|
Obviously should only be used on lists :)
|
||||||
|
|
||||||
|
A default limit can be set by setting `limit` on the object. This will also
|
||||||
|
be used as the maximum if the client sets the `limit` GET param
|
||||||
|
"""
|
||||||
|
limit = 20
|
||||||
|
|
||||||
|
def get_limit(self):
|
||||||
|
""" Helper method to determine what the `limit` should be """
|
||||||
|
try:
|
||||||
|
limit = int(self.request.GET.get('limit', self.limit))
|
||||||
|
return min(limit, self.limit)
|
||||||
|
except ValueError:
|
||||||
|
return self.limit
|
||||||
|
|
||||||
|
def url_with_page_number(self, page_number):
|
||||||
|
""" Constructs a url used for getting the next/previous urls """
|
||||||
|
url = "%s?page=%d" % (self.request.path, page_number)
|
||||||
|
|
||||||
|
limit = self.get_limit()
|
||||||
|
if limit != self.limit:
|
||||||
|
url = "%s&limit=%d" % (url, limit)
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
def next(self, page):
|
||||||
|
""" Returns a url to the next page of results (if any) """
|
||||||
|
if not page.has_next():
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.url_with_page_number(page.next_page_number())
|
||||||
|
|
||||||
|
def previous(self, page):
|
||||||
|
""" Returns a url to the previous page of results (if any) """
|
||||||
|
if not page.has_previous():
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.url_with_page_number(page.previous_page_number())
|
||||||
|
|
||||||
|
def serialize_page_info(self, page):
|
||||||
|
""" This is some useful information that is added to the response """
|
||||||
|
return {
|
||||||
|
'next': self.next(page),
|
||||||
|
'page': page.number,
|
||||||
|
'pages': page.paginator.num_pages,
|
||||||
|
'per_page': self.get_limit(),
|
||||||
|
'previous': self.previous(page),
|
||||||
|
'total': page.paginator.count,
|
||||||
|
}
|
||||||
|
|
||||||
|
def filter_response(self, obj):
|
||||||
|
"""
|
||||||
|
Given the response content, paginate and then serialize.
|
||||||
|
|
||||||
|
The response is modified to include to useful data relating to the number
|
||||||
|
of objects, number of pages, next/previous urls etc. etc.
|
||||||
|
|
||||||
|
The serialised objects are put into `results` on this new, modified
|
||||||
|
response
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We don't want to paginate responses for anything other than GET requests
|
||||||
|
if self.method.upper() != 'GET':
|
||||||
|
return self._resource.filter_response(obj)
|
||||||
|
|
||||||
|
paginator = Paginator(obj, self.get_limit())
|
||||||
|
|
||||||
|
try:
|
||||||
|
page_num = int(self.request.GET.get('page', '1'))
|
||||||
|
except ValueError:
|
||||||
|
page_num = 1
|
||||||
|
|
||||||
|
if page_num not in paginator.page_range:
|
||||||
|
raise ErrorResponse(status.HTTP_404_NOT_FOUND, {'detail': 'That page contains no results'})
|
||||||
|
|
||||||
|
page = paginator.page(page_num)
|
||||||
|
|
||||||
|
serialized_object_list = self._resource.filter_response(page.object_list)
|
||||||
|
serialized_page_info = self.serialize_page_info(page)
|
||||||
|
|
||||||
|
serialized_page_info['results'] = serialized_object_list
|
||||||
|
|
||||||
|
return serialized_page_info
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user