Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework/generics.py: 82%

102 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2Generic views that provide commonly needed behaviour. 

3""" 

4from django.core.exceptions import ValidationError 

5from django.db.models.query import QuerySet 

6from django.http import Http404 

7from django.shortcuts import get_object_or_404 as _get_object_or_404 

8 

9from rest_framework import mixins, views 

10from rest_framework.settings import api_settings 

11 

12 

13def get_object_or_404(queryset, *filter_args, **filter_kwargs): 

14 """ 

15 Same as Django's standard shortcut, but make sure to also raise 404 

16 if the filter_kwargs don't match the required types. 

17 """ 

18 try: 

19 return _get_object_or_404(queryset, *filter_args, **filter_kwargs) 

20 except (TypeError, ValueError, ValidationError): 

21 raise Http404 

22 

23 

24class GenericAPIView(views.APIView): 

25 """ 

26 Base class for all other generic views. 

27 """ 

28 # You'll need to either set these attributes, 

29 # or override `get_queryset()`/`get_serializer_class()`. 

30 # If you are overriding a view method, it is important that you call 

31 # `get_queryset()` instead of accessing the `queryset` property directly, 

32 # as `queryset` will get evaluated only once, and those results are cached 

33 # for all subsequent requests. 

34 queryset = None 

35 serializer_class = None 

36 

37 # If you want to use object lookups other than pk, set 'lookup_field'. 

38 # For more complex lookup requirements override `get_object()`. 

39 lookup_field = 'pk' 

40 lookup_url_kwarg = None 

41 

42 # The filter backend classes to use for queryset filtering 

43 filter_backends = api_settings.DEFAULT_FILTER_BACKENDS 

44 

45 # The style to use for queryset pagination. 

46 pagination_class = api_settings.DEFAULT_PAGINATION_CLASS 

47 

48 def get_queryset(self): 

49 """ 

50 Get the list of items for this view. 

51 This must be an iterable, and may be a queryset. 

52 Defaults to using `self.queryset`. 

53 

54 This method should always be used rather than accessing `self.queryset` 

55 directly, as `self.queryset` gets evaluated only once, and those results 

56 are cached for all subsequent requests. 

57 

58 You may want to override this if you need to provide different 

59 querysets depending on the incoming request. 

60 

61 (Eg. return a list of items that is specific to the user) 

62 """ 

63 assert self.queryset is not None, ( 

64 "'%s' should either include a `queryset` attribute, " 

65 "or override the `get_queryset()` method." 

66 % self.__class__.__name__ 

67 ) 

68 

69 queryset = self.queryset 

70 if isinstance(queryset, QuerySet): 70 ↛ 73line 70 didn't jump to line 73, because the condition on line 70 was never false

71 # Ensure queryset is re-evaluated on each request. 

72 queryset = queryset.all() 

73 return queryset 

74 

75 def get_object(self): 

76 """ 

77 Returns the object the view is displaying. 

78 

79 You may want to override this if you need to provide non-standard 

80 queryset lookups. Eg if objects are referenced using multiple 

81 keyword arguments in the url conf. 

82 """ 

83 queryset = self.filter_queryset(self.get_queryset()) 

84 

85 # Perform the lookup filtering. 

86 lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field 

87 

88 assert lookup_url_kwarg in self.kwargs, ( 

89 'Expected view %s to be called with a URL keyword argument ' 

90 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 

91 'attribute on the view correctly.' % 

92 (self.__class__.__name__, lookup_url_kwarg) 

93 ) 

94 

95 filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} 

96 obj = get_object_or_404(queryset, **filter_kwargs) 

97 

98 # May raise a permission denied 

99 self.check_object_permissions(self.request, obj) 

100 

101 return obj 

102 

103 def get_serializer(self, *args, **kwargs): 

104 """ 

105 Return the serializer instance that should be used for validating and 

106 deserializing input, and for serializing output. 

107 """ 

108 serializer_class = self.get_serializer_class() 

109 kwargs.setdefault('context', self.get_serializer_context()) 

110 return serializer_class(*args, **kwargs) 

111 

112 def get_serializer_class(self): 

113 """ 

114 Return the class to use for the serializer. 

115 Defaults to using `self.serializer_class`. 

116 

117 You may want to override this if you need to provide different 

118 serializations depending on the incoming request. 

119 

120 (Eg. admins get full serialization, others get basic serialization) 

121 """ 

122 assert self.serializer_class is not None, ( 

123 "'%s' should either include a `serializer_class` attribute, " 

124 "or override the `get_serializer_class()` method." 

125 % self.__class__.__name__ 

126 ) 

127 

128 return self.serializer_class 

129 

130 def get_serializer_context(self): 

131 """ 

132 Extra context provided to the serializer class. 

133 """ 

134 return { 

135 'request': self.request, 

136 'format': self.format_kwarg, 

137 'view': self 

138 } 

139 

140 def filter_queryset(self, queryset): 

141 """ 

142 Given a queryset, filter it with whichever filter backend is in use. 

143 

144 You are unlikely to want to override this method, although you may need 

145 to call it either from a list view, or from a custom `get_object` 

146 method if you want to apply the configured filtering backend to the 

147 default queryset. 

148 """ 

149 for backend in list(self.filter_backends): 

150 queryset = backend().filter_queryset(self.request, queryset, self) 

151 return queryset 

152 

153 @property 

154 def paginator(self): 

155 """ 

156 The paginator instance associated with the view, or `None`. 

157 """ 

158 if not hasattr(self, '_paginator'): 

159 if self.pagination_class is None: 159 ↛ 160line 159 didn't jump to line 160, because the condition on line 159 was never true

160 self._paginator = None 

161 else: 

162 self._paginator = self.pagination_class() 

163 return self._paginator 

164 

165 def paginate_queryset(self, queryset): 

166 """ 

167 Return a single page of results, or `None` if pagination is disabled. 

168 """ 

169 if self.paginator is None: 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true

170 return None 

171 return self.paginator.paginate_queryset(queryset, self.request, view=self) 

172 

173 def get_paginated_response(self, data): 

174 """ 

175 Return a paginated style `Response` object for the given output data. 

176 """ 

177 assert self.paginator is not None 

178 return self.paginator.get_paginated_response(data) 

179 

180 

181# Concrete view classes that provide method handlers 

182# by composing the mixin classes with the base view. 

183 

184class CreateAPIView(mixins.CreateModelMixin, 

185 GenericAPIView): 

186 """ 

187 Concrete view for creating a model instance. 

188 """ 

189 def post(self, request, *args, **kwargs): 

190 return self.create(request, *args, **kwargs) 

191 

192 

193class ListAPIView(mixins.ListModelMixin, 

194 GenericAPIView): 

195 """ 

196 Concrete view for listing a queryset. 

197 """ 

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

199 return self.list(request, *args, **kwargs) 

200 

201 

202class RetrieveAPIView(mixins.RetrieveModelMixin, 

203 GenericAPIView): 

204 """ 

205 Concrete view for retrieving a model instance. 

206 """ 

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

208 return self.retrieve(request, *args, **kwargs) 

209 

210 

211class DestroyAPIView(mixins.DestroyModelMixin, 

212 GenericAPIView): 

213 """ 

214 Concrete view for deleting a model instance. 

215 """ 

216 def delete(self, request, *args, **kwargs): 

217 return self.destroy(request, *args, **kwargs) 

218 

219 

220class UpdateAPIView(mixins.UpdateModelMixin, 

221 GenericAPIView): 

222 """ 

223 Concrete view for updating a model instance. 

224 """ 

225 def put(self, request, *args, **kwargs): 

226 return self.update(request, *args, **kwargs) 

227 

228 def patch(self, request, *args, **kwargs): 

229 return self.partial_update(request, *args, **kwargs) 

230 

231 

232class ListCreateAPIView(mixins.ListModelMixin, 

233 mixins.CreateModelMixin, 

234 GenericAPIView): 

235 """ 

236 Concrete view for listing a queryset or creating a model instance. 

237 """ 

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

239 return self.list(request, *args, **kwargs) 

240 

241 def post(self, request, *args, **kwargs): 

242 return self.create(request, *args, **kwargs) 

243 

244 

245class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, 

246 mixins.UpdateModelMixin, 

247 GenericAPIView): 

248 """ 

249 Concrete view for retrieving, updating a model instance. 

250 """ 

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

252 return self.retrieve(request, *args, **kwargs) 

253 

254 def put(self, request, *args, **kwargs): 

255 return self.update(request, *args, **kwargs) 

256 

257 def patch(self, request, *args, **kwargs): 

258 return self.partial_update(request, *args, **kwargs) 

259 

260 

261class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, 

262 mixins.DestroyModelMixin, 

263 GenericAPIView): 

264 """ 

265 Concrete view for retrieving or deleting a model instance. 

266 """ 

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

268 return self.retrieve(request, *args, **kwargs) 

269 

270 def delete(self, request, *args, **kwargs): 

271 return self.destroy(request, *args, **kwargs) 

272 

273 

274class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, 

275 mixins.UpdateModelMixin, 

276 mixins.DestroyModelMixin, 

277 GenericAPIView): 

278 """ 

279 Concrete view for retrieving, updating or deleting a model instance. 

280 """ 

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

282 return self.retrieve(request, *args, **kwargs) 

283 

284 def put(self, request, *args, **kwargs): 

285 return self.update(request, *args, **kwargs) 

286 

287 def patch(self, request, *args, **kwargs): 

288 return self.partial_update(request, *args, **kwargs) 

289 

290 def delete(self, request, *args, **kwargs): 

291 return self.destroy(request, *args, **kwargs)