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

1from django.http import HttpResponse 

2 

3from .loader import get_template, select_template 

4 

5 

6class ContentNotRenderedError(Exception): 

7 pass 

8 

9 

10class SimpleTemplateResponse(HttpResponse): 

11 rendering_attrs = ["template_name", "context_data", "_post_render_callbacks"] 

12 

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 

28 

29 self.using = using 

30 

31 self._post_render_callbacks = [] 

32 

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 

40 

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) 

45 

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 

52 

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] 

66 

67 return obj_dict 

68 

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 

77 

78 def resolve_context(self, context): 

79 return context 

80 

81 @property 

82 def rendered_content(self): 

83 """Return the freshly rendered content for the template and context 

84 described by the TemplateResponse. 

85 

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) 

93 

94 def add_post_render_callback(self, callback): 

95 """Add a new post-rendering callback. 

96 

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) 

104 

105 def render(self): 

106 """Render (thereby finalizing) the content of the response. 

107 

108 If the content has already been rendered, this is a no-op. 

109 

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 

120 

121 @property 

122 def is_rendered(self): 

123 return self._is_rendered 

124 

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__() 

131 

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 

139 

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 

145 

146 

147class TemplateResponse(SimpleTemplateResponse): 

148 rendering_attrs = SimpleTemplateResponse.rendering_attrs + ["_request"] 

149 

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