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

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 

7 

8 

9class MultipleObjectMixin(ContextMixin): 

10 """A mixin for views manipulating multiple objects.""" 

11 

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 

21 

22 def get_queryset(self): 

23 """ 

24 Return the list of items for this view. 

25 

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) 

46 

47 return queryset 

48 

49 def get_ordering(self): 

50 """Return the field or fields to use for ordering the queryset.""" 

51 return self.ordering 

52 

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 ) 

80 

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 

86 

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 ) 

98 

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 

105 

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 

112 

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 

121 

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) 

148 

149 

150class BaseListView(MultipleObjectMixin, View): 

151 """A base view for displaying a list of objects.""" 

152 

153 def get(self, request, *args, **kwargs): 

154 self.object_list = self.get_queryset() 

155 allow_empty = self.get_allow_empty() 

156 

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) 

176 

177 

178class MultipleObjectTemplateResponseMixin(TemplateResponseMixin): 

179 """Mixin for responding with a template and list of objects.""" 

180 

181 template_name_suffix = "_list" 

182 

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 = [] 

194 

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 

214 

215 

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 """