Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Paginator._get_page hook

This allows for Paginator subclasses to easily override the Page class
that gets used.

Took the opportunity to also do some non-invasive PEP8 tidying of the
paginator module.
  • Loading branch information...
commit fbfa654a15487f9a49e9a5d34a4e9694fe878a8f 1 parent 8fdb282
@SmileyChris SmileyChris authored
View
39 django/core/paginator.py
@@ -7,14 +7,19 @@
class InvalidPage(Exception):
pass
+
class PageNotAnInteger(InvalidPage):
pass
+
class EmptyPage(InvalidPage):
pass
+
class Paginator(object):
- def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
+
+ def __init__(self, object_list, per_page, orphans=0,
+ allow_empty_first_page=True):
self.object_list = object_list
self.per_page = int(per_page)
self.orphans = int(orphans)
@@ -22,7 +27,9 @@ def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True
self._num_pages = self._count = None
def validate_number(self, number):
- "Validates the given 1-based page number."
+ """
+ Validates the given 1-based page number.
+ """
try:
number = int(number)
except (TypeError, ValueError):
@@ -37,16 +44,29 @@ def validate_number(self, number):
return number
def page(self, number):
- "Returns a Page object for the given 1-based page number."
+ """
+ Returns a Page object for the given 1-based page number.
+ """
number = self.validate_number(number)
bottom = (number - 1) * self.per_page
top = bottom + self.per_page
if top + self.orphans >= self.count:
top = self.count
- return Page(self.object_list[bottom:top], number, self)
+ return self._get_page(self.object_list[bottom:top], number, self)
+
+ def _get_page(self, *args, **kwargs):
+ """
+ Returns an instance of a single page.
+
+ This hook can be used by subclasses to use an alternative to the
+ standard :cls:`Page` object.
+ """
+ return Page(*args, **kwargs)
def _get_count(self):
- "Returns the total number of objects, across all pages."
+ """
+ Returns the total number of objects, across all pages.
+ """
if self._count is None:
try:
self._count = self.object_list.count()
@@ -59,7 +79,9 @@ def _get_count(self):
count = property(_get_count)
def _get_num_pages(self):
- "Returns the total number of pages."
+ """
+ Returns the total number of pages.
+ """
if self._num_pages is None:
if self.count == 0 and not self.allow_empty_first_page:
self._num_pages = 0
@@ -77,9 +99,12 @@ def _get_page_range(self):
return range(1, self.num_pages + 1)
page_range = property(_get_page_range)
-QuerySetPaginator = Paginator # For backwards-compatibility.
+
+QuerySetPaginator = Paginator # For backwards-compatibility.
+
class Page(collections.Sequence):
+
def __init__(self, object_list, number, paginator):
self.object_list = object_list
self.number = number
View
20 tests/regressiontests/pagination/custom.py
@@ -0,0 +1,20 @@
+from django.core.paginator import Paginator, Page
+
+
+class ValidAdjacentNumsPage(Page):
+
+ def next_page_number(self):
+ if not self.has_next():
+ return None
+ return super(ValidAdjacentNumsPage, self).next_page_number()
+
+ def previous_page_number(self):
+ if not self.has_previous():
+ return None
+ return super(ValidAdjacentNumsPage, self).previous_page_number()
+
+
+class ValidAdjacentNumsPaginator(Paginator):
+
+ def _get_page(self, *args, **kwargs):
+ return ValidAdjacentNumsPage(*args, **kwargs)
View
15 tests/regressiontests/pagination/tests.py
@@ -9,6 +9,7 @@
from django.utils import unittest
from .models import Article
+from .custom import ValidAdjacentNumsPaginator
class PaginationTests(unittest.TestCase):
@@ -217,6 +218,20 @@ def test_page_sequence(self):
self.assertEqual(''.join(page2), 'fghijk')
self.assertEqual(''.join(reversed(page2)), 'kjihgf')
+ def test_get_page_hook(self):
+ """
+ Tests that a Paginator subclass can use the ``_get_page`` hook to
+ return an alternative to the standard Page class.
+ """
+ eleven = 'abcdefghijk'
+ paginator = ValidAdjacentNumsPaginator(eleven, per_page=6)
+ page1 = paginator.page(1)
+ page2 = paginator.page(2)
+ self.assertEquals(page1.previous_page_number(), None)
+ self.assertEquals(page1.next_page_number(), 2)
+ self.assertEquals(page2.previous_page_number(), 1)
+ self.assertEquals(page2.next_page_number(), None)
+
class ModelPaginationTests(TestCase):
"""
Please sign in to comment.
Something went wrong with that request. Please try again.