Fixed #14773 -- Modified MultipleObjectMixin to allow for custom paginators. 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
This commit is contained in:
parent
23a19240da
commit
ee48da2405
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -32,7 +33,7 @@ class MultipleObjectMixin(object):
|
||||||
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)
|
||||||
|
@ -55,6 +56,12 @@ class MultipleObjectMixin(object):
|
||||||
"""
|
"""
|
||||||
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``
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||||
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']
|
||||||
|
@ -86,6 +86,21 @@ class ListViewTests(TestCase):
|
||||||
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)
|
||||||
|
|
|
@ -117,6 +117,10 @@ urlpatterns = patterns('',
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue