Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/template/response.py: 51%
69 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.http import HttpResponse
3from .loader import get_template, select_template
6class ContentNotRenderedError(Exception):
7 pass
10class SimpleTemplateResponse(HttpResponse):
11 rendering_attrs = ["template_name", "context_data", "_post_render_callbacks"]
13 def __init__(
14 self,
15 template,
16 context=None,
17 content_type=None,
18 status=None,
19 charset=None,
20 using=None,
21 headers=None,
22 ):
23 # It would seem obvious to call these next two members 'template' and
24 # 'context', but those names are reserved as part of the test Client
25 # API. To avoid the name collision, we use different names.
26 self.template_name = template
27 self.context_data = context
29 self.using = using
31 self._post_render_callbacks = []
33 # _request stores the current request object in subclasses that know
34 # about requests, like TemplateResponse. It's defined in the base class
35 # to minimize code duplication.
36 # It's called self._request because self.request gets overwritten by
37 # django.test.client.Client. Unlike template_name and context_data,
38 # _request should not be considered part of the public API.
39 self._request = None
41 # content argument doesn't make sense here because it will be replaced
42 # with rendered template so we always pass empty string in order to
43 # prevent errors and provide shorter signature.
44 super().__init__("", content_type, status, charset=charset, headers=headers)
46 # _is_rendered tracks whether the template and context has been baked
47 # into a final response.
48 # Super __init__ doesn't know any better than to set self.content to
49 # the empty string we just gave it, which wrongly sets _is_rendered
50 # True, so we initialize it to False after the call to super __init__.
51 self._is_rendered = False
53 def __getstate__(self):
54 """
55 Raise an exception if trying to pickle an unrendered response. Pickle
56 only rendered data, not the data used to construct the response.
57 """
58 obj_dict = self.__dict__.copy()
59 if not self._is_rendered:
60 raise ContentNotRenderedError(
61 "The response content must be rendered before it can be pickled."
62 )
63 for attr in self.rendering_attrs:
64 if attr in obj_dict:
65 del obj_dict[attr]
67 return obj_dict
69 def resolve_template(self, template):
70 """Accept a template object, path-to-template, or list of paths."""
71 if isinstance(template, (list, tuple)):
72 return select_template(template, using=self.using)
73 elif isinstance(template, str):
74 return get_template(template, using=self.using)
75 else:
76 return template
78 def resolve_context(self, context):
79 return context
81 @property
82 def rendered_content(self):
83 """Return the freshly rendered content for the template and context
84 described by the TemplateResponse.
86 This *does not* set the final content of the response. To set the
87 response content, you must either call render(), or set the
88 content explicitly using the value of this property.
89 """
90 template = self.resolve_template(self.template_name)
91 context = self.resolve_context(self.context_data)
92 return template.render(context, self._request)
94 def add_post_render_callback(self, callback):
95 """Add a new post-rendering callback.
97 If the response has already been rendered,
98 invoke the callback immediately.
99 """
100 if self._is_rendered:
101 callback(self)
102 else:
103 self._post_render_callbacks.append(callback)
105 def render(self):
106 """Render (thereby finalizing) the content of the response.
108 If the content has already been rendered, this is a no-op.
110 Return the baked response instance.
111 """
112 retval = self
113 if not self._is_rendered: 113 ↛ 119line 113 didn't jump to line 119, because the condition on line 113 was never false
114 self.content = self.rendered_content
115 for post_callback in self._post_render_callbacks: 115 ↛ 116line 115 didn't jump to line 116, because the loop on line 115 never started
116 newretval = post_callback(retval)
117 if newretval is not None:
118 retval = newretval
119 return retval
121 @property
122 def is_rendered(self):
123 return self._is_rendered
125 def __iter__(self):
126 if not self._is_rendered:
127 raise ContentNotRenderedError(
128 "The response content must be rendered before it can be iterated over."
129 )
130 return super().__iter__()
132 @property
133 def content(self):
134 if not self._is_rendered: 134 ↛ 135line 134 didn't jump to line 135, because the condition on line 134 was never true
135 raise ContentNotRenderedError(
136 "The response content must be rendered before it can be accessed."
137 )
138 return super().content
140 @content.setter
141 def content(self, value):
142 """Set the content for the response."""
143 HttpResponse.content.fset(self, value)
144 self._is_rendered = True
147class TemplateResponse(SimpleTemplateResponse):
148 rendering_attrs = SimpleTemplateResponse.rendering_attrs + ["_request"]
150 def __init__(
151 self,
152 request,
153 template,
154 context=None,
155 content_type=None,
156 status=None,
157 charset=None,
158 using=None,
159 headers=None,
160 ):
161 super().__init__(
162 template, context, content_type, status, charset, using, headers=headers
163 )
164 self._request = request