1
from __future__ import unicode_literals
1
3
from django.core.paginator import Paginator, InvalidPage
2
4
from django.core.exceptions import ImproperlyConfigured
3
5
from django.http import Http404
4
from django.utils.encoding import smart_str
5
6
from django.utils.translation import ugettext as _
6
from django.views.generic.base import TemplateResponseMixin, View
9
class MultipleObjectMixin(object):
7
from django.views.generic.base import TemplateResponseMixin, ContextMixin, View
10
class MultipleObjectMixin(ContextMixin):
12
A mixin for views manipulating multiple objects.
14
18
context_object_name = None
15
19
paginator_class = Paginator
17
22
def get_queryset(self):
19
Get the list of items for this view. This must be an interable, and may
24
Get the list of items for this view. This must be an iterable, and may
20
25
be a queryset (in which qs-specific behavior will be enabled).
22
27
if self.queryset is not None:
26
31
elif self.model is not None:
27
32
queryset = self.model._default_manager.all()
29
raise ImproperlyConfigured(u"'%s' must define 'queryset' or 'model'"
34
raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'"
30
35
% self.__class__.__name__)
35
40
Paginate the queryset, if needed.
37
42
paginator = self.get_paginator(queryset, page_size, allow_empty_first_page=self.get_allow_empty())
38
page = self.kwargs.get('page') or self.request.GET.get('page') or 1
43
page_kwarg = self.page_kwarg
44
page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1
40
46
page_number = int(page)
43
49
page_number = paginator.num_pages
45
raise Http404(_(u"Page is not 'last', nor can it be converted to an int."))
51
raise Http404(_("Page is not 'last', nor can it be converted to an int."))
47
53
page = paginator.page(page_number)
48
54
return (paginator, page, page.object_list, page.has_other_pages())
50
raise Http404(_(u'Invalid page (%(page_number)s)') % {
51
'page_number': page_number
55
except InvalidPage as e:
56
raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
57
'page_number': page_number,
54
61
def get_paginate_by(self, queryset):
77
84
if self.context_object_name:
78
85
return self.context_object_name
79
86
elif hasattr(object_list, 'model'):
80
return smart_str('%s_list' % object_list.model._meta.object_name.lower())
87
return '%s_list' % object_list.model._meta.object_name.lower()
103
110
'is_paginated': False,
104
111
'object_list': queryset
106
context.update(kwargs)
107
113
if context_object_name is not None:
108
114
context[context_object_name] = queryset
115
context.update(kwargs)
116
return super(MultipleObjectMixin, self).get_context_data(**context)
112
119
class BaseListView(MultipleObjectMixin, View):
121
A base view for displaying a list of objects.
113
123
def get(self, request, *args, **kwargs):
114
124
self.object_list = self.get_queryset()
115
125
allow_empty = self.get_allow_empty()
116
if not allow_empty and len(self.object_list) == 0:
117
raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
118
% {'class_name': self.__class__.__name__})
128
# When pagination is enabled and object_list is a queryset,
129
# it's better to do a cheap query than to load the unpaginated
130
# queryset in memory.
131
if (self.get_paginate_by(self.object_list) is not None
132
and hasattr(self.object_list, 'exists')):
133
is_empty = not self.object_list.exists()
135
is_empty = len(self.object_list) == 0
137
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
138
% {'class_name': self.__class__.__name__})
119
139
context = self.get_context_data(object_list=self.object_list)
120
140
return self.render_to_response(context)
123
143
class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
145
Mixin for responding with a template and list of objects.
124
147
template_name_suffix = '_list'
126
149
def get_template_names(self):
128
151
Return a list of template names to be used for the request. Must return
129
a list. May not be called if get_template is overridden.
152
a list. May not be called if render_to_response is overridden.
132
155
names = super(MultipleObjectTemplateResponseMixin, self).get_template_names()