Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/views/generic/list.py: 28%
99 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from django.core.exceptions import ImproperlyConfigured
2from django.core.paginator import InvalidPage, Paginator
3from django.db.models import QuerySet
4from django.http import Http404
5from django.utils.translation import gettext as _
6from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
9class MultipleObjectMixin(ContextMixin):
10 """A mixin for views manipulating multiple objects."""
12 allow_empty = True
13 queryset = None
14 model = None
15 paginate_by = None
16 paginate_orphans = 0
17 context_object_name = None
18 paginator_class = Paginator
19 page_kwarg = "page"
20 ordering = None
22 def get_queryset(self):
23 """
24 Return the list of items for this view.
26 The return value must be an iterable and may be an instance of
27 `QuerySet` in which case `QuerySet` specific behavior will be enabled.
28 """
29 if self.queryset is not None:
30 queryset = self.queryset
31 if isinstance(queryset, QuerySet):
32 queryset = queryset.all()
33 elif self.model is not None:
34 queryset = self.model._default_manager.all()
35 else:
36 raise ImproperlyConfigured(
37 "%(cls)s is missing a QuerySet. Define "
38 "%(cls)s.model, %(cls)s.queryset, or override "
39 "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__}
40 )
41 ordering = self.get_ordering()
42 if ordering:
43 if isinstance(ordering, str):
44 ordering = (ordering,)
45 queryset = queryset.order_by(*ordering)
47 return queryset
49 def get_ordering(self):
50 """Return the field or fields to use for ordering the queryset."""
51 return self.ordering
53 def paginate_queryset(self, queryset, page_size):
54 """Paginate the queryset, if needed."""
55 paginator = self.get_paginator(
56 queryset,
57 page_size,
58 orphans=self.get_paginate_orphans(),
59 allow_empty_first_page=self.get_allow_empty(),
60 )
61 page_kwarg = self.page_kwarg
62 page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1
63 try:
64 page_number = int(page)
65 except ValueError:
66 if page == "last":
67 page_number = paginator.num_pages
68 else:
69 raise Http404(
70 _("Page is not “last”, nor can it be converted to an int.")
71 )
72 try:
73 page = paginator.page(page_number)
74 return (paginator, page, page.object_list, page.has_other_pages())
75 except InvalidPage as e:
76 raise Http404(
77 _("Invalid page (%(page_number)s): %(message)s")
78 % {"page_number": page_number, "message": str(e)}
79 )
81 def get_paginate_by(self, queryset):
82 """
83 Get the number of items to paginate by, or ``None`` for no pagination.
84 """
85 return self.paginate_by
87 def get_paginator(
88 self, queryset, per_page, orphans=0, allow_empty_first_page=True, **kwargs
89 ):
90 """Return an instance of the paginator for this view."""
91 return self.paginator_class(
92 queryset,
93 per_page,
94 orphans=orphans,
95 allow_empty_first_page=allow_empty_first_page,
96 **kwargs,
97 )
99 def get_paginate_orphans(self):
100 """
101 Return the maximum number of orphans extend the last page by when
102 paginating.
103 """
104 return self.paginate_orphans
106 def get_allow_empty(self):
107 """
108 Return ``True`` if the view should display empty lists and ``False``
109 if a 404 should be raised instead.
110 """
111 return self.allow_empty
113 def get_context_object_name(self, object_list):
114 """Get the name of the item to be used in the context."""
115 if self.context_object_name:
116 return self.context_object_name
117 elif hasattr(object_list, "model"):
118 return "%s_list" % object_list.model._meta.model_name
119 else:
120 return None
122 def get_context_data(self, *, object_list=None, **kwargs):
123 """Get the context for this view."""
124 queryset = object_list if object_list is not None else self.object_list
125 page_size = self.get_paginate_by(queryset)
126 context_object_name = self.get_context_object_name(queryset)
127 if page_size:
128 paginator, page, queryset, is_paginated = self.paginate_queryset(
129 queryset, page_size
130 )
131 context = {
132 "paginator": paginator,
133 "page_obj": page,
134 "is_paginated": is_paginated,
135 "object_list": queryset,
136 }
137 else:
138 context = {
139 "paginator": None,
140 "page_obj": None,
141 "is_paginated": False,
142 "object_list": queryset,
143 }
144 if context_object_name is not None:
145 context[context_object_name] = queryset
146 context.update(kwargs)
147 return super().get_context_data(**context)
150class BaseListView(MultipleObjectMixin, View):
151 """A base view for displaying a list of objects."""
153 def get(self, request, *args, **kwargs):
154 self.object_list = self.get_queryset()
155 allow_empty = self.get_allow_empty()
157 if not allow_empty:
158 # When pagination is enabled and object_list is a queryset,
159 # it's better to do a cheap query than to load the unpaginated
160 # queryset in memory.
161 if self.get_paginate_by(self.object_list) is not None and hasattr(
162 self.object_list, "exists"
163 ):
164 is_empty = not self.object_list.exists()
165 else:
166 is_empty = not self.object_list
167 if is_empty:
168 raise Http404(
169 _("Empty list and “%(class_name)s.allow_empty” is False.")
170 % {
171 "class_name": self.__class__.__name__,
172 }
173 )
174 context = self.get_context_data()
175 return self.render_to_response(context)
178class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):
179 """Mixin for responding with a template and list of objects."""
181 template_name_suffix = "_list"
183 def get_template_names(self):
184 """
185 Return a list of template names to be used for the request. Must return
186 a list. May not be called if render_to_response is overridden.
187 """
188 try:
189 names = super().get_template_names()
190 except ImproperlyConfigured:
191 # If template_name isn't specified, it's not a problem --
192 # we just start with an empty list.
193 names = []
195 # If the list is a queryset, we'll invent a template name based on the
196 # app and model name. This name gets put at the end of the template
197 # name list so that user-supplied names override the automatically-
198 # generated ones.
199 if hasattr(self.object_list, "model"):
200 opts = self.object_list.model._meta
201 names.append(
202 "%s/%s%s.html"
203 % (opts.app_label, opts.model_name, self.template_name_suffix)
204 )
205 elif not names:
206 raise ImproperlyConfigured(
207 "%(cls)s requires either a 'template_name' attribute "
208 "or a get_queryset() method that returns a QuerySet."
209 % {
210 "cls": self.__class__.__name__,
211 }
212 )
213 return names
216class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
217 """
218 Render some list of objects, set by `self.model` or `self.queryset`.
219 `self.queryset` can actually be any iterable of items, not just a queryset.
220 """