mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-07 13:54:47 +03:00
Merge 33d656e5e8
into 0b373be712
This commit is contained in:
commit
1d3883e2d3
|
@ -15,8 +15,9 @@ from django.utils import six
|
|||
from django.utils.six.moves.urllib import parse as urlparse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.compat import template_render
|
||||
from rest_framework.exceptions import NotFound
|
||||
from rest_framework.exceptions import APIException, NotFound
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.utils.urls import remove_query_param, replace_query_param
|
||||
|
@ -723,3 +724,67 @@ class CursorPagination(BasePagination):
|
|||
|
||||
def get_fields(self, view):
|
||||
return [self.cursor_query_param]
|
||||
|
||||
|
||||
class IncorrectLimitOffsetError(APIException):
|
||||
status_code = status.HTTP_400_BAD_REQUEST
|
||||
default_detail = _('Incorrect offset or limit.')
|
||||
|
||||
|
||||
class NoCountsLimitOffsetPagination(LimitOffsetPagination):
|
||||
"""
|
||||
A limit/offset based pagination, without performing counts. For example:
|
||||
|
||||
http://api.example.org/accounts/?limit=100 - will return first 100 items
|
||||
http://api.example.org/accounts/?offset=400&limit=100 - will returns 100 items starting from 401th
|
||||
http://api.example.org/accounts/?offset=-50&limit=100 - will return first 50 items
|
||||
|
||||
Pros:
|
||||
- no counts
|
||||
- easier to use than cursor pagination (especially if you need sorting)
|
||||
- works with angular ui-scroll (which requires negative offsets)
|
||||
|
||||
Cons:
|
||||
- html is not handled
|
||||
- skip is a relatively slow operation, so this paginator is not as fast as cursor paginator when you use
|
||||
large offsets
|
||||
"""
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
self.limit = self.get_limit(request)
|
||||
if self.limit is None:
|
||||
raise IncorrectLimitOffsetError
|
||||
|
||||
self.offset = self.get_offset(request)
|
||||
if self.offset < 0:
|
||||
self.limit += self.offset # + because offset is negative
|
||||
self.offset = 0
|
||||
if self.limit <= 0:
|
||||
raise IncorrectLimitOffsetError
|
||||
|
||||
self.request = request
|
||||
self.results = list(queryset[self.offset:self.offset + self.limit])
|
||||
return self.results
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
return Response(OrderedDict([
|
||||
('next', self.get_next_link()),
|
||||
('previous', self.get_previous_link()),
|
||||
('results', data)
|
||||
]))
|
||||
return self.default_limit
|
||||
|
||||
def get_offset(self, request):
|
||||
try:
|
||||
return int(request.query_params[self.offset_query_param])
|
||||
except (KeyError, ValueError):
|
||||
return 0
|
||||
|
||||
def get_next_link(self):
|
||||
if len(self.results) < self.limit:
|
||||
return None
|
||||
|
||||
url = self.request.build_absolute_uri()
|
||||
url = replace_query_param(url, self.limit_query_param, self.limit)
|
||||
|
||||
offset = self.offset + self.limit
|
||||
return replace_query_param(url, self.offset_query_param, offset)
|
||||
|
|
Loading…
Reference in New Issue
Block a user