Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/views/generic/detail.py: 28%

79 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.db import models 

3from django.http import Http404 

4from django.utils.translation import gettext as _ 

5from django.views.generic.base import ContextMixin, TemplateResponseMixin, View 

6 

7 

8class SingleObjectMixin(ContextMixin): 

9 """ 

10 Provide the ability to retrieve a single object for further manipulation. 

11 """ 

12 

13 model = None 

14 queryset = None 

15 slug_field = "slug" 

16 context_object_name = None 

17 slug_url_kwarg = "slug" 

18 pk_url_kwarg = "pk" 

19 query_pk_and_slug = False 

20 

21 def get_object(self, queryset=None): 

22 """ 

23 Return the object the view is displaying. 

24 

25 Require `self.queryset` and a `pk` or `slug` argument in the URLconf. 

26 Subclasses can override this to return any object. 

27 """ 

28 # Use a custom queryset if provided; this is required for subclasses 

29 # like DateDetailView 

30 if queryset is None: 

31 queryset = self.get_queryset() 

32 

33 # Next, try looking up by primary key. 

34 pk = self.kwargs.get(self.pk_url_kwarg) 

35 slug = self.kwargs.get(self.slug_url_kwarg) 

36 if pk is not None: 

37 queryset = queryset.filter(pk=pk) 

38 

39 # Next, try looking up by slug. 

40 if slug is not None and (pk is None or self.query_pk_and_slug): 

41 slug_field = self.get_slug_field() 

42 queryset = queryset.filter(**{slug_field: slug}) 

43 

44 # If none of those are defined, it's an error. 

45 if pk is None and slug is None: 

46 raise AttributeError( 

47 "Generic detail view %s must be called with either an object " 

48 "pk or a slug in the URLconf." % self.__class__.__name__ 

49 ) 

50 

51 try: 

52 # Get the single item from the filtered queryset 

53 obj = queryset.get() 

54 except queryset.model.DoesNotExist: 

55 raise Http404( 

56 _("No %(verbose_name)s found matching the query") 

57 % {"verbose_name": queryset.model._meta.verbose_name} 

58 ) 

59 return obj 

60 

61 def get_queryset(self): 

62 """ 

63 Return the `QuerySet` that will be used to look up the object. 

64 

65 This method is called by the default implementation of get_object() and 

66 may not be called if get_object() is overridden. 

67 """ 

68 if self.queryset is None: 

69 if self.model: 

70 return self.model._default_manager.all() 

71 else: 

72 raise ImproperlyConfigured( 

73 "%(cls)s is missing a QuerySet. Define " 

74 "%(cls)s.model, %(cls)s.queryset, or override " 

75 "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__} 

76 ) 

77 return self.queryset.all() 

78 

79 def get_slug_field(self): 

80 """Get the name of a slug field to be used to look up by slug.""" 

81 return self.slug_field 

82 

83 def get_context_object_name(self, obj): 

84 """Get the name to use for the object.""" 

85 if self.context_object_name: 

86 return self.context_object_name 

87 elif isinstance(obj, models.Model): 

88 return obj._meta.model_name 

89 else: 

90 return None 

91 

92 def get_context_data(self, **kwargs): 

93 """Insert the single object into the context dict.""" 

94 context = {} 

95 if self.object: 

96 context["object"] = self.object 

97 context_object_name = self.get_context_object_name(self.object) 

98 if context_object_name: 

99 context[context_object_name] = self.object 

100 context.update(kwargs) 

101 return super().get_context_data(**context) 

102 

103 

104class BaseDetailView(SingleObjectMixin, View): 

105 """A base view for displaying a single object.""" 

106 

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

108 self.object = self.get_object() 

109 context = self.get_context_data(object=self.object) 

110 return self.render_to_response(context) 

111 

112 

113class SingleObjectTemplateResponseMixin(TemplateResponseMixin): 

114 template_name_field = None 

115 template_name_suffix = "_detail" 

116 

117 def get_template_names(self): 

118 """ 

119 Return a list of template names to be used for the request. May not be 

120 called if render_to_response() is overridden. Return the following list: 

121 

122 * the value of ``template_name`` on the view (if provided) 

123 * the contents of the ``template_name_field`` field on the 

124 object instance that the view is operating upon (if available) 

125 * ``<app_label>/<model_name><template_name_suffix>.html`` 

126 """ 

127 try: 

128 names = super().get_template_names() 

129 except ImproperlyConfigured: 

130 # If template_name isn't specified, it's not a problem -- 

131 # we just start with an empty list. 

132 names = [] 

133 

134 # If self.template_name_field is set, grab the value of the field 

135 # of that name from the object; this is the most specific template 

136 # name, if given. 

137 if self.object and self.template_name_field: 

138 name = getattr(self.object, self.template_name_field, None) 

139 if name: 

140 names.insert(0, name) 

141 

142 # The least-specific option is the default <app>/<model>_detail.html; 

143 # only use this if the object in question is a model. 

144 if isinstance(self.object, models.Model): 

145 object_meta = self.object._meta 

146 names.append( 

147 "%s/%s%s.html" 

148 % ( 

149 object_meta.app_label, 

150 object_meta.model_name, 

151 self.template_name_suffix, 

152 ) 

153 ) 

154 elif getattr(self, "model", None) is not None and issubclass( 

155 self.model, models.Model 

156 ): 

157 names.append( 

158 "%s/%s%s.html" 

159 % ( 

160 self.model._meta.app_label, 

161 self.model._meta.model_name, 

162 self.template_name_suffix, 

163 ) 

164 ) 

165 

166 # If we still haven't managed to find any template names, we should 

167 # re-raise the ImproperlyConfigured to alert the user. 

168 if not names: 

169 raise 

170 

171 return names 

172 

173 

174class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView): 

175 """ 

176 Render a "detail" view of an object. 

177 

178 By default this is a model instance looked up from `self.queryset`, but the 

179 view will support display of *any* object by overriding `self.get_object()`. 

180 """