Skip to content

Commit

Permalink
Fixed #28032 -- Added Paginator.get_page().
Browse files Browse the repository at this point in the history
Moved boilerplate from docs to a method.
  • Loading branch information
sjlehtin authored and timgraham committed Sep 6, 2017
1 parent 5b1c389 commit 407c124
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 9 deletions.
13 changes: 13 additions & 0 deletions django/core/paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ def validate_number(self, number):
raise EmptyPage(_('That page contains no results'))
return number

def get_page(self, number):
"""
Return a valid page, even if the page argument isn't a number or isn't
in range.
"""
try:
number = self.validate_number(number)
except PageNotAnInteger:
number = 1
except EmptyPage:
number = self.num_pages
return self.page(number)

def page(self, number):
"""Return a Page object for the given 1-based page number."""
number = self.validate_number(number)
Expand Down
6 changes: 6 additions & 0 deletions docs/releases/2.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ Models
* Added support for expressions in :attr:`Meta.ordering
<django.db.models.Options.ordering>`.

Pagination
~~~~~~~~~~

* Added :meth:`Paginator.get_page() <django.core.paginator.Paginator.get_page>`
to provide the documented pattern of handling invalid page numbers.

Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~

Expand Down
24 changes: 15 additions & 9 deletions docs/topics/pagination.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,7 @@ The view function looks like this::
paginator = Paginator(contact_list, 25) # Show 25 contacts per page

page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
contacts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
contacts = paginator.page(paginator.num_pages)

contacts = paginator.get_page(page)
return render(request, 'list.html', {'contacts': contacts})

In the template :file:`list.html`, you'll want to include navigation between
Expand Down Expand Up @@ -177,6 +169,20 @@ Optional arguments
Methods
-------

.. method:: Paginator.get_page(number)

.. versionadded:: 2.0

Returns a :class:`Page` object with the given 1-based index, while also
handling out of range and invalid page numbers.

If the page isn't a number, it returns the first page. If the page number
is negative or greater than the number of pages, it returns the last page.

It raises an exception (:exc:`EmptyPage`) only if you specify
``Paginator(..., allow_empty_first_page=False)`` and the ``object_list`` is
empty.

.. method:: Paginator.page(number)

Returns a :class:`Page` object with the given 1-based index. Raises
Expand Down
32 changes: 32 additions & 0 deletions tests/pagination/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,38 @@ def test_page_range_iterator(self):
"""
self.assertIsInstance(Paginator([1, 2, 3], 2).page_range, type(range(0)))

def test_get_page(self):
"""
Paginator.get_page() returns a valid page even with invalid page
arguments.
"""
paginator = Paginator([1, 2, 3], 2)
page = paginator.get_page(1)
self.assertEqual(page.number, 1)
self.assertEqual(page.object_list, [1, 2])
# An empty page returns the last page.
self.assertEqual(paginator.get_page(3).number, 2)
# Non-integer page returns the first page.
self.assertEqual(paginator.get_page(None).number, 1)

def test_get_page_empty_object_list(self):
"""Paginator.get_page() with an empty object_list."""
paginator = Paginator([], 2)
# An empty page returns the last page.
self.assertEqual(paginator.get_page(1).number, 1)
self.assertEqual(paginator.get_page(2).number, 1)
# Non-integer page returns the first page.
self.assertEqual(paginator.get_page(None).number, 1)

def test_get_page_empty_object_list_and_allow_empty_first_page_false(self):
"""
Paginator.get_page() raises EmptyPage if allow_empty_first_page=False
and object_list is empty.
"""
paginator = Paginator([], 2, allow_empty_first_page=False)
with self.assertRaises(EmptyPage):
paginator.get_page(1)


class ModelPaginationTests(TestCase):
"""
Expand Down

0 comments on commit 407c124

Please sign in to comment.