Skip to content

Commit

Permalink
Merge pull request #3631 from syphar/paginat
Browse files Browse the repository at this point in the history
allow setting a custom Django Paginator class
  • Loading branch information
tomchristie committed Nov 30, 2015
2 parents bd8098e + 3806af3 commit 832d632
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/api-guide/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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 @@ -169,6 +169,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 @@ -195,7 +197,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

0 comments on commit 832d632

Please sign in to comment.