Commit fbfa654a authored by Chris Beaven's avatar Chris Beaven
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.
parent 8fdb2821
Loading
Loading
Loading
Loading
+32 −7
Original line number Diff line number Diff line
@@ -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.


class Page(collections.Sequence):

    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
+20 −0
Original line number Diff line number Diff line
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)
+15 −0
Original line number Diff line number Diff line
@@ -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):
    """