Skip to content

Commit c5425ac

Browse files
committed
Fixed admin pagination when limit is 0.
1 parent 22695ec commit c5425ac

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

rest_framework/pagination.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,22 @@ def get_paginated_response(self, data):
313313
('results', data)
314314
]))
315315

316+
def get_zero_limit(self):
317+
# By default we return max_limit, but one could also return default_limit.
318+
return self.max_limit
319+
316320
def get_limit(self, request):
317321
if self.limit_query_param:
318322
try:
319-
return _positive_int(
323+
limit = _positive_int(
320324
request.query_params[self.limit_query_param],
321325
cutoff=self.max_limit
322326
)
327+
# User can specify limit == 0 to specify max (and not default) limit.
328+
# By default (max_limit is None) this disables pagination.
329+
if limit == 0:
330+
limit = self.get_zero_limit()
331+
return limit
323332
except (KeyError, ValueError):
324333
pass
325334

@@ -357,7 +366,23 @@ def get_previous_link(self):
357366
return replace_query_param(url, self.offset_query_param, offset)
358367

359368
def get_html_context(self):
369+
# paginate_queryset should be called before, to set
370+
# self.limit and other values on self.
371+
372+
if self.limit is None:
373+
return {
374+
'previous_url': None,
375+
'next_url': None,
376+
'page_links': []
377+
}
378+
360379
base_url = self.request.build_absolute_uri()
380+
381+
# This changes the URL in fact only when limit is 0 (which makes limit == max_limit)
382+
# or when limit is missing (which makes it default_limit). We want to inform
383+
# the user what this effective limit is.
384+
base_url = replace_query_param(base_url, self.limit_query_param, self.limit)
385+
361386
current = _divide_with_ceil(self.offset, self.limit) + 1
362387
# The number of pages is a little bit fiddly.
363388
# We need to sum both the number of pages from current offset to end

tests/test_pagination.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,10 @@ class ExamplePagination(pagination.LimitOffsetPagination):
322322
self.queryset = range(1, 101)
323323

324324
def paginate_queryset(self, request):
325-
return list(self.pagination.paginate_queryset(self.queryset, request))
325+
queryset = self.pagination.paginate_queryset(self.queryset, request)
326+
if queryset is None:
327+
return None
328+
return list(queryset)
326329

327330
def get_paginated_content(self, queryset):
328331
response = self.pagination.get_paginated_response(queryset)
@@ -505,6 +508,52 @@ def test_max_limit(self):
505508
assert content.get('next') == next_url
506509
assert content.get('previous') == prev_url
507510

511+
def test_limit_is_zero(self):
512+
"""
513+
A limit of zero should set limit to max_limit.
514+
"""
515+
offset = 20
516+
request = Request(factory.get('/', {'limit': 0, 'offset': offset}))
517+
queryset = self.paginate_queryset(request)
518+
content = self.get_paginated_content(queryset)
519+
context = self.get_html_context()
520+
assert queryset == self.queryset[20:35]
521+
assert content == {
522+
'results': self.queryset[20:35],
523+
'previous': 'http://testserver/?limit=15&offset=5',
524+
'next': 'http://testserver/?limit=15&offset=35',
525+
'count': 100
526+
}
527+
assert context == {
528+
'previous_url': 'http://testserver/?limit=15&offset=5',
529+
'next_url': 'http://testserver/?limit=15&offset=35',
530+
'page_links': [
531+
PageLink('http://testserver/?limit=15', 1, False, False),
532+
PageLink('http://testserver/?limit=15&offset=5', 2, False, False),
533+
PageLink('http://testserver/?limit=15&offset=20', 3, True, False),
534+
PageLink('http://testserver/?limit=15&offset=35', 4, False, False),
535+
PAGE_BREAK,
536+
PageLink('http://testserver/?limit=15&offset=95', 8, False, False),
537+
]
538+
}
539+
540+
def test_limit_is_zero_with_no_limit(self):
541+
"""
542+
A limit of zero should set limit to max_limit, but when it is None,
543+
pagination should be disabled and whole queryset returned.
544+
"""
545+
self.pagination.max_limit = None
546+
offset = 30
547+
request = Request(factory.get('/', {'limit': 0, 'offset': offset}))
548+
queryset = self.paginate_queryset(request)
549+
context = self.get_html_context()
550+
assert queryset is None
551+
assert context == {
552+
'previous_url': None,
553+
'next_url': None,
554+
'page_links': []
555+
}
556+
508557

509558
class TestCursorPagination:
510559
"""

0 commit comments

Comments
 (0)