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.
This commit is contained in:
parent
8fdb28219d
commit
fbfa654a15
|
@ -7,14 +7,19 @@ from django.utils import six
|
|||
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 @@ class Paginator(object):
|
|||
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 @@ class Paginator(object):
|
|||
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 @@ class Paginator(object):
|
|||
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 @@ class Paginator(object):
|
|||
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
|
||||
|
|
|
@ -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)
|
|
@ -9,6 +9,7 @@ from django.utils import six
|
|||
from django.utils import unittest
|
||||
|
||||
from .models import Article
|
||||
from .custom import ValidAdjacentNumsPaginator
|
||||
|
||||
|
||||
class PaginationTests(unittest.TestCase):
|
||||
|
@ -217,6 +218,20 @@ class PaginationTests(unittest.TestCase):
|
|||
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):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue