Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/views/generic/base.py: 56%
111 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
1import logging
3from django.core.exceptions import ImproperlyConfigured
4from django.http import (
5 HttpResponse,
6 HttpResponseGone,
7 HttpResponseNotAllowed,
8 HttpResponsePermanentRedirect,
9 HttpResponseRedirect,
10)
11from django.template.response import TemplateResponse
12from django.urls import reverse
13from django.utils.decorators import classonlymethod
15logger = logging.getLogger("django.request")
18class ContextMixin:
19 """
20 A default context mixin that passes the keyword arguments received by
21 get_context_data() as the template context.
22 """
24 extra_context = None
26 def get_context_data(self, **kwargs):
27 kwargs.setdefault("view", self)
28 if self.extra_context is not None:
29 kwargs.update(self.extra_context)
30 return kwargs
33class View:
34 """
35 Intentionally simple parent class for all views. Only implements
36 dispatch-by-method and simple sanity checking.
37 """
39 http_method_names = [
40 "get",
41 "post",
42 "put",
43 "patch",
44 "delete",
45 "head",
46 "options",
47 "trace",
48 ]
50 def __init__(self, **kwargs):
51 """
52 Constructor. Called in the URLconf; can contain helpful extra
53 keyword arguments, and other things.
54 """
55 # Go through keyword arguments, and either save their values to our
56 # instance, or raise an error.
57 for key, value in kwargs.items():
58 setattr(self, key, value)
60 @classonlymethod
61 def as_view(cls, **initkwargs):
62 """Main entry point for a request-response process."""
63 for key in initkwargs:
64 if key in cls.http_method_names: 64 ↛ 65line 64 didn't jump to line 65, because the condition on line 64 was never true
65 raise TypeError(
66 "The method name %s is not accepted as a keyword argument "
67 "to %s()." % (key, cls.__name__)
68 )
69 if not hasattr(cls, key): 69 ↛ 70line 69 didn't jump to line 70, because the condition on line 69 was never true
70 raise TypeError(
71 "%s() received an invalid keyword %r. as_view "
72 "only accepts arguments that are already "
73 "attributes of the class." % (cls.__name__, key)
74 )
76 def view(request, *args, **kwargs):
77 self = cls(**initkwargs)
78 self.setup(request, *args, **kwargs)
79 if not hasattr(self, "request"): 79 ↛ 80line 79 didn't jump to line 80, because the condition on line 79 was never true
80 raise AttributeError(
81 "%s instance has no 'request' attribute. Did you override "
82 "setup() and forget to call super()?" % cls.__name__
83 )
84 return self.dispatch(request, *args, **kwargs)
86 view.view_class = cls
87 view.view_initkwargs = initkwargs
89 # __name__ and __qualname__ are intentionally left unchanged as
90 # view_class should be used to robustly determine the name of the view
91 # instead.
92 view.__doc__ = cls.__doc__
93 view.__module__ = cls.__module__
94 view.__annotations__ = cls.dispatch.__annotations__
95 # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
96 # the dispatch method.
97 view.__dict__.update(cls.dispatch.__dict__)
99 return view
101 def setup(self, request, *args, **kwargs):
102 """Initialize attributes shared by all view methods."""
103 if hasattr(self, "get") and not hasattr(self, "head"): 103 ↛ 104line 103 didn't jump to line 104, because the condition on line 103 was never true
104 self.head = self.get
105 self.request = request
106 self.args = args
107 self.kwargs = kwargs
109 def dispatch(self, request, *args, **kwargs):
110 # Try to dispatch to the right method; if a method doesn't exist,
111 # defer to the error handler. Also defer to the error handler if the
112 # request method isn't on the approved list.
113 if request.method.lower() in self.http_method_names:
114 handler = getattr(
115 self, request.method.lower(), self.http_method_not_allowed
116 )
117 else:
118 handler = self.http_method_not_allowed
119 return handler(request, *args, **kwargs)
121 def http_method_not_allowed(self, request, *args, **kwargs):
122 logger.warning(
123 "Method Not Allowed (%s): %s",
124 request.method,
125 request.path,
126 extra={"status_code": 405, "request": request},
127 )
128 return HttpResponseNotAllowed(self._allowed_methods())
130 def options(self, request, *args, **kwargs):
131 """Handle responding to requests for the OPTIONS HTTP verb."""
132 response = HttpResponse()
133 response.headers["Allow"] = ", ".join(self._allowed_methods())
134 response.headers["Content-Length"] = "0"
135 return response
137 def _allowed_methods(self):
138 return [m.upper() for m in self.http_method_names if hasattr(self, m)]
141class TemplateResponseMixin:
142 """A mixin that can be used to render a template."""
144 template_name = None
145 template_engine = None
146 response_class = TemplateResponse
147 content_type = None
149 def render_to_response(self, context, **response_kwargs):
150 """
151 Return a response, using the `response_class` for this view, with a
152 template rendered with the given context.
154 Pass response_kwargs to the constructor of the response class.
155 """
156 response_kwargs.setdefault("content_type", self.content_type)
157 return self.response_class(
158 request=self.request,
159 template=self.get_template_names(),
160 context=context,
161 using=self.template_engine,
162 **response_kwargs,
163 )
165 def get_template_names(self):
166 """
167 Return a list of template names to be used for the request. Must return
168 a list. May not be called if render_to_response() is overridden.
169 """
170 if self.template_name is None:
171 raise ImproperlyConfigured(
172 "TemplateResponseMixin requires either a definition of "
173 "'template_name' or an implementation of 'get_template_names()'"
174 )
175 else:
176 return [self.template_name]
179class TemplateView(TemplateResponseMixin, ContextMixin, View):
180 """
181 Render a template. Pass keyword arguments from the URLconf to the context.
182 """
184 def get(self, request, *args, **kwargs):
185 context = self.get_context_data(**kwargs)
186 return self.render_to_response(context)
189class RedirectView(View):
190 """Provide a redirect on any GET request."""
192 permanent = False
193 url = None
194 pattern_name = None
195 query_string = False
197 def get_redirect_url(self, *args, **kwargs):
198 """
199 Return the URL redirect to. Keyword arguments from the URL pattern
200 match generating the redirect request are provided as kwargs to this
201 method.
202 """
203 if self.url:
204 url = self.url % kwargs
205 elif self.pattern_name:
206 url = reverse(self.pattern_name, args=args, kwargs=kwargs)
207 else:
208 return None
210 args = self.request.META.get("QUERY_STRING", "")
211 if args and self.query_string:
212 url = "%s?%s" % (url, args)
213 return url
215 def get(self, request, *args, **kwargs):
216 url = self.get_redirect_url(*args, **kwargs)
217 if url:
218 if self.permanent:
219 return HttpResponsePermanentRedirect(url)
220 else:
221 return HttpResponseRedirect(url)
222 else:
223 logger.warning(
224 "Gone: %s", request.path, extra={"status_code": 410, "request": request}
225 )
226 return HttpResponseGone()
228 def head(self, request, *args, **kwargs):
229 return self.get(request, *args, **kwargs)
231 def post(self, request, *args, **kwargs):
232 return self.get(request, *args, **kwargs)
234 def options(self, request, *args, **kwargs):
235 return self.get(request, *args, **kwargs)
237 def delete(self, request, *args, **kwargs):
238 return self.get(request, *args, **kwargs)
240 def put(self, request, *args, **kwargs):
241 return self.get(request, *args, **kwargs)
243 def patch(self, request, *args, **kwargs):
244 return self.get(request, *args, **kwargs)