Skip to content

Commit

Permalink
Fixed #14773 -- Modified MultipleObjectMixin to allow for custom pagi…
Browse files Browse the repository at this point in the history
…nators. Thanks to piquadrat for the report and initial patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14828 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Dec 5, 2010
1 parent 23a1924 commit ee48da2
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 2 deletions.
9 changes: 8 additions & 1 deletion django/views/generic/list.py
Expand Up @@ -10,6 +10,7 @@ class MultipleObjectMixin(object):
model = None model = None
paginate_by = None paginate_by = None
context_object_name = None context_object_name = None
paginator_class = Paginator


def get_queryset(self): def get_queryset(self):
""" """
Expand All @@ -32,7 +33,7 @@ def paginate_queryset(self, queryset, page_size):
Paginate the queryset, if needed. Paginate the queryset, if needed.
""" """
if queryset.count() > page_size: if queryset.count() > page_size:
paginator = Paginator(queryset, page_size, allow_empty_first_page=self.get_allow_empty()) paginator = self.get_paginator(queryset, page_size, allow_empty_first_page=self.get_allow_empty())
page = self.kwargs.get('page', None) or self.request.GET.get('page', 1) page = self.kwargs.get('page', None) or self.request.GET.get('page', 1)
try: try:
page_number = int(page) page_number = int(page)
Expand All @@ -55,6 +56,12 @@ def get_paginate_by(self, queryset):
""" """
return self.paginate_by return self.paginate_by


def get_paginator(self, queryset, per_page, orphans=0, allow_empty_first_page=True):
"""
Return an instance of the paginator for this view.
"""
return self.paginator_class(queryset, per_page, orphans=orphans, allow_empty_first_page=allow_empty_first_page)

def get_allow_empty(self): def get_allow_empty(self):
""" """
Returns ``True`` if the view should display empty lists, and ``False`` Returns ``True`` if the view should display empty lists, and ``False``
Expand Down
13 changes: 13 additions & 0 deletions docs/ref/class-based-views.txt
Expand Up @@ -305,6 +305,14 @@ MultipleObjectMixin
expect either a ``page`` query string parameter (via ``GET``) or a expect either a ``page`` query string parameter (via ``GET``) or a
``page`` variable specified in the URLconf. ``page`` variable specified in the URLconf.


.. attribute:: paginator_class

The paginator class to be used for pagination. By default,
:class:`django.core.paginator.Paginator` is used. If the custom paginator
class doesn't have the same constructor interface as
:class:`django.core.paginator.Paginator`, you will also need to
provide an implementation for :meth:`MultipleObjectMixin.get_paginator`.

.. attribute:: context_object_name .. attribute:: context_object_name


Designates the name of the variable to use in the context. Designates the name of the variable to use in the context.
Expand All @@ -329,6 +337,11 @@ MultipleObjectMixin
pagination. By default this simply returns the value of pagination. By default this simply returns the value of
:attr:`MultipleObjectMixin.paginate_by`. :attr:`MultipleObjectMixin.paginate_by`.


.. method:: get_paginator(queryset, queryset, per_page, orphans=0, allow_empty_first_page=True)

Returns an instance of the paginator to use for this view. By default,
instantiates an instance of :attr:`paginator_class`.

.. method:: get_allow_empty() .. method:: get_allow_empty()


Return a boolean specifying whether to display the page if no objects Return a boolean specifying whether to display the page if no objects
Expand Down
17 changes: 16 additions & 1 deletion tests/regressiontests/generic_views/list.py
Expand Up @@ -2,7 +2,7 @@
from django.test import TestCase from django.test import TestCase


from regressiontests.generic_views.models import Author from regressiontests.generic_views.models import Author

from regressiontests.generic_views.views import CustomPaginator


class ListViewTests(TestCase): class ListViewTests(TestCase):
fixtures = ['generic-views-test-data.json'] fixtures = ['generic-views-test-data.json']
Expand Down Expand Up @@ -86,6 +86,21 @@ def test_paginated_invalid_page(self):
res = self.client.get('/list/authors/paginated/?page=frog') res = self.client.get('/list/authors/paginated/?page=frog')
self.assertEqual(res.status_code, 404) self.assertEqual(res.status_code, 404)


def test_paginated_custom_paginator_class(self):
self._make_authors(7)
res = self.client.get('/list/authors/paginated/custom_class/')
self.assertEqual(res.status_code, 200)
self.assertIsInstance(res.context['paginator'], CustomPaginator)
# Custom pagination allows for 2 orphans on a page size of 5
self.assertEqual(len(res.context['object_list']), 7)

def test_paginated_custom_paginator_constructor(self):
self._make_authors(7)
res = self.client.get('/list/authors/paginated/custom_constructor/')
self.assertEqual(res.status_code, 200)
# Custom pagination allows for 2 orphans on a page size of 5
self.assertEqual(len(res.context['object_list']), 7)

def test_allow_empty_false(self): def test_allow_empty_false(self):
res = self.client.get('/list/authors/notempty/') res = self.client.get('/list/authors/notempty/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
Expand Down
4 changes: 4 additions & 0 deletions tests/regressiontests/generic_views/urls.py
Expand Up @@ -117,6 +117,10 @@
views.AuthorList.as_view(context_object_name='object_list')), views.AuthorList.as_view(context_object_name='object_list')),
(r'^list/authors/invalid/$', (r'^list/authors/invalid/$',
views.AuthorList.as_view(queryset=None)), views.AuthorList.as_view(queryset=None)),
(r'^list/authors/paginated/custom_class/$',
views.AuthorList.as_view(paginate_by=5, paginator_class=views.CustomPaginator)),
(r'^list/authors/paginated/custom_constructor/$',
views.AuthorListCustomPaginator.as_view()),


# YearArchiveView # YearArchiveView
# Mixing keyword and possitional captures below is intentional; the views # Mixing keyword and possitional captures below is intentional; the views
Expand Down
18 changes: 18 additions & 0 deletions tests/regressiontests/generic_views/views.py
@@ -1,4 +1,5 @@
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views import generic from django.views import generic
Expand Down Expand Up @@ -50,6 +51,23 @@ class AuthorList(generic.ListView):
queryset = Author.objects.all() queryset = Author.objects.all()




class CustomPaginator(Paginator):
def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
super(CustomPaginator, self).__init__(
queryset,
page_size,
orphans=2,
allow_empty_first_page=allow_empty_first_page)

class AuthorListCustomPaginator(AuthorList):
paginate_by = 5;

def get_paginator(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
return super(AuthorListCustomPaginator, self).get_paginator(
queryset,
page_size,
orphans=2,
allow_empty_first_page=allow_empty_first_page)


class ArtistCreate(generic.CreateView): class ArtistCreate(generic.CreateView):
model = Artist model = Artist
Expand Down

0 comments on commit ee48da2

Please sign in to comment.