summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami J. Lehtinen <sjl@iki.fi>2017-04-06 13:01:04 +0300
committerTim Graham <timograham@gmail.com>2017-09-06 14:17:19 -0400
commit407c1249c9a0296ec8a8d95e447bd695ca471b5e (patch)
treea181ef463ae796575f0c507bd80b3a9d5d6b79d4
parent5b1c389603a353625ae1603ba345147356336afb (diff)
Fixed #28032 -- Added Paginator.get_page().
Moved boilerplate from docs to a method.
-rw-r--r--django/core/paginator.py13
-rw-r--r--docs/releases/2.0.txt6
-rw-r--r--docs/topics/pagination.txt24
-rw-r--r--tests/pagination/tests.py32
4 files changed, 66 insertions, 9 deletions
diff --git a/django/core/paginator.py b/django/core/paginator.py
index 2686957af0..b07be513d3 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -47,6 +47,19 @@ class Paginator:
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)
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index dd8183d798..e50bd36d93 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -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
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/pagination.txt b/docs/topics/pagination.txt
index 2521fee312..bc936faaef 100644
--- a/docs/topics/pagination.txt
+++ b/docs/topics/pagination.txt
@@ -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
@@ -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
diff --git a/tests/pagination/tests.py b/tests/pagination/tests.py
index 530f908027..05fad4f67c 100644
--- a/tests/pagination/tests.py
+++ b/tests/pagination/tests.py
@@ -242,6 +242,38 @@ class PaginationTests(unittest.TestCase):
"""
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):
"""