Skip to content

allow setting a custom Django Paginator in pagination.PageNumberPagin… #3631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api-guide/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ The `PageNumberPagination` class includes a number of attributes that may be ove

To set these attributes you should override the `PageNumberPagination` class, and then enable your custom pagination class as above.

* `django_paginator_class` - The Django Paginator class to use. Default is `django.core.paginator.Paginator`, which should be fine for most usecases.
* `page_size` - A numeric value indicating the page size. If set, this overrides the `PAGE_SIZE` setting. Defaults to the same value as the `PAGE_SIZE` settings key.
* `page_query_param` - A string value indicating the name of the query parameter to use for the pagination control.
* `page_size_query_param` - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to `None`, indicating that the client may not control the requested page size.
Expand Down
4 changes: 3 additions & 1 deletion rest_framework/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class PageNumberPagination(BasePagination):
# Defaults to `None`, meaning pagination is disabled.
page_size = api_settings.PAGE_SIZE

django_paginator_class = DjangoPaginator

# Client can control the page using this query parameter.
page_query_param = 'page'

Expand All @@ -194,7 +196,7 @@ def paginate_queryset(self, queryset, request, view=None):
if not page_size:
return None

paginator = DjangoPaginator(queryset, page_size)
paginator = self.django_paginator_class(queryset, page_size)
page_number = request.query_params.get(self.page_query_param, 1)
if page_number in self.last_page_strings:
page_number = paginator.num_pages
Expand Down
59 changes: 59 additions & 0 deletions tests/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import unicode_literals

import pytest
from django.core.paginator import Paginator as DjangoPaginator

from rest_framework import (
exceptions, filters, generics, pagination, serializers, status
Expand Down Expand Up @@ -249,6 +250,64 @@ def test_invalid_page(self):
self.paginate_queryset(request)


class TestPageNumberPaginationOverride:
"""
Unit tests for `pagination.PageNumberPagination`.

the Django Paginator Class is overridden.
"""

def setup(self):
class OverriddenDjangoPaginator(DjangoPaginator):
# override the count in our overriden Django Paginator
# we will only return one page, with one item
count = 1

class ExamplePagination(pagination.PageNumberPagination):
django_paginator_class = OverriddenDjangoPaginator
page_size = 5

self.pagination = ExamplePagination()
self.queryset = range(1, 101)

def paginate_queryset(self, request):
return list(self.pagination.paginate_queryset(self.queryset, request))

def get_paginated_content(self, queryset):
response = self.pagination.get_paginated_response(queryset)
return response.data

def get_html_context(self):
return self.pagination.get_html_context()

def test_no_page_number(self):
request = Request(factory.get('/'))
queryset = self.paginate_queryset(request)
content = self.get_paginated_content(queryset)
context = self.get_html_context()
assert queryset == [1]
assert content == {
'results': [1, ],
'previous': None,
'next': None,
'count': 1
}
assert context == {
'previous_url': None,
'next_url': None,
'page_links': [
PageLink('http://testserver/', 1, True, False),
]
}
assert not self.pagination.display_page_controls
assert isinstance(self.pagination.to_html(), type(''))

def test_invalid_page(self):
request = Request(factory.get('/', {'page': 'invalid'}))
with pytest.raises(exceptions.NotFound):
self.paginate_queryset(request)


class TestLimitOffset:
"""
Unit tests for `pagination.LimitOffsetPagination`.
Expand Down