1
0
mirror of https://github.com/django/django.git synced 2025-10-30 17:16:10 +00:00

Fixed #15012 -- Added post-rendering callbacks to TemplateResponse so that decorators (in particular, the cache decorator) can defer processing until after rendering has occurred. Thanks to Joshua Ginsberg for the draft patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15295 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee
2011-01-24 14:24:35 +00:00
parent 3d7afd5d2b
commit 3f528e10d5
9 changed files with 256 additions and 8 deletions

View File

@@ -19,12 +19,30 @@ class SimpleTemplateResponse(HttpResponse):
# a final response.
self._is_rendered = False
self._post_render_callbacks = []
# content argument doesn't make sense here because it will be replaced
# with rendered template so we always pass empty string in order to
# prevent errors and provide shorter signature.
super(SimpleTemplateResponse, self).__init__('', mimetype, status,
content_type)
def __getstate__(self):
"""Pickling support function.
Ensures that the object can't be pickled before it has been
rendered, and that the pickled state only includes rendered
data, not the data used to construct the response.
"""
obj_dict = self.__dict__.copy()
if not self._is_rendered:
raise ContentNotRenderedError('The response content must be rendered before it can be pickled.')
del obj_dict['template_name']
del obj_dict['context_data']
del obj_dict['_post_render_callbacks']
return obj_dict
def resolve_template(self, template):
"Accepts a template object, path-to-template or list of paths"
if isinstance(template, (list, tuple)):
@@ -57,6 +75,16 @@ class SimpleTemplateResponse(HttpResponse):
content = template.render(context)
return content
def add_post_render_callback(self, callback):
"""Add a new post-rendering callback.
If the response has already been rendered, invoke the callback immediately.
"""
if self._is_rendered:
callback(self)
else:
self._post_render_callbacks.append(callback)
def render(self):
"""Render (thereby finalizing) the content of the response.
@@ -66,6 +94,8 @@ class SimpleTemplateResponse(HttpResponse):
"""
if not self._is_rendered:
self._set_content(self.rendered_content)
for post_callback in self._post_render_callbacks:
post_callback(self)
return self
is_rendered = property(lambda self: self._is_rendered)
@@ -81,7 +111,7 @@ class SimpleTemplateResponse(HttpResponse):
return super(SimpleTemplateResponse, self)._get_content()
def _set_content(self, value):
"Overrides rendered content, unless you later call render()"
"Sets the content for the response"
super(SimpleTemplateResponse, self)._set_content(value)
self._is_rendered = True
@@ -101,6 +131,20 @@ class TemplateResponse(SimpleTemplateResponse):
super(TemplateResponse, self).__init__(
template, context, mimetype, status, content_type)
def __getstate__(self):
"""Pickling support function.
Ensures that the object can't be pickled before it has been
rendered, and that the pickled state only includes rendered
data, not the data used to construct the response.
"""
obj_dict = super(TemplateResponse, self).__getstate__()
del obj_dict['_request']
del obj_dict['_current_app']
return obj_dict
def resolve_context(self, context):
"""Convert context data into a full RequestContext object
(assuming it isn't already a Context object).
@@ -109,3 +153,5 @@ class TemplateResponse(SimpleTemplateResponse):
return context
else:
return RequestContext(self._request, context, current_app=self._current_app)