mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 19:14:01 +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.core.paginator import Paginator
|
||||
from django.db.models.query import QuerySet
|
||||
from django.db.models.fields.related import ForeignKey
|
||||
from django.http import HttpResponse
|
||||
|
@ -637,4 +638,92 @@ class ListModelMixin(object):
|
|||
queryset = queryset.order_by(*args)
|
||||
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