Ticket #16326: patch-16326-niran-2.diff

File patch-16326-niran-2.diff, 6.4 KB (added by natrius, 4 years ago)
  • django/template/response.py

    diff --git a/django/template/response.py b/django/template/response.py
    index 73645a7..fce9c48 100644
    a b from django.template import loader, Context, RequestContext 
    44class ContentNotRenderedError(Exception):
    55    pass
    66
     7class DiscardedAttributeError(AttributeError):
     8    pass
     9
    710class SimpleTemplateResponse(HttpResponse):
    811
     12    RENDERING_ATTRS = ['template_name', 'context_data',
     13        '_post_render_callbacks']
     14
    915    def __init__(self, template, context=None, mimetype=None, status=None,
    1016            content_type=None):
    1117        # It would seem obvious to call these next two members 'template' and
    class SimpleTemplateResponse(HttpResponse): 
    3743        obj_dict = self.__dict__.copy()
    3844        if not self._is_rendered:
    3945            raise ContentNotRenderedError('The response content must be rendered before it can be pickled.')
    40         del obj_dict['template_name']
    41         del obj_dict['context_data']
    42         del obj_dict['_post_render_callbacks']
     46        for attr in self.RENDERING_ATTRS:
     47            if attr in obj_dict:
     48                del obj_dict[attr]
    4349
    4450        return obj_dict
    4551
     52    def __getattr__(self, name):
     53        if name in self.RENDERING_ATTRS:
     54            raise DiscardedAttributeError('The %s attribute was discarded when this TemplateResponse was pickled.' % name)
     55        return super(SimpleTemplateResponse, self).__getattr__(name)
     56
    4657    def resolve_template(self, template):
    4758        "Accepts a template object, path-to-template or list of paths"
    4859        if isinstance(template, (list, tuple)):
    class SimpleTemplateResponse(HttpResponse): 
    120131
    121132    content = property(_get_content, _set_content)
    122133
    123 
    124134class TemplateResponse(SimpleTemplateResponse):
     135
     136    RENDERING_ATTRS = SimpleTemplateResponse.RENDERING_ATTRS + \
     137        ['_request', '_current_app']
     138
    125139    def __init__(self, request, template, context=None, mimetype=None,
    126140            status=None, content_type=None, current_app=None):
    127141        # self.request gets over-written by django.test.client.Client - and
    class TemplateResponse(SimpleTemplateResponse): 
    134148        super(TemplateResponse, self).__init__(
    135149            template, context, mimetype, status, content_type)
    136150
    137     def __getstate__(self):
    138         """Pickling support function.
    139 
    140         Ensures that the object can't be pickled before it has been
    141         rendered, and that the pickled state only includes rendered
    142         data, not the data used to construct the response.
    143         """
    144         obj_dict = super(TemplateResponse, self).__getstate__()
    145 
    146         del obj_dict['_request']
    147         del obj_dict['_current_app']
    148 
    149         return obj_dict
    150 
    151151    def resolve_context(self, context):
    152152        """Convert context data into a full RequestContext object
    153153        (assuming it isn't already a Context object).
  • tests/regressiontests/templates/response.py

    diff --git a/tests/regressiontests/templates/response.py b/tests/regressiontests/templates/response.py
    index 6fc2ded..2c7eb41 100644
    a b from django.conf import settings 
    88import django.template.context
    99from django.template import Template, Context, RequestContext
    1010from django.template.response import (TemplateResponse, SimpleTemplateResponse,
    11                                       ContentNotRenderedError)
     11                                      ContentNotRenderedError,
     12                                      DiscardedAttributeError)
    1213
    1314def test_processor(request):
    1415    return {'processors': 'yes'}
    class SimpleTemplateResponseTest(BaseTemplateResponseTest): 
    190191
    191192        # ...and the unpickled reponse doesn't have the
    192193        # template-related attributes, so it can't be re-rendered
    193         self.assertFalse(hasattr(unpickled_response, 'template_name'))
    194         self.assertFalse(hasattr(unpickled_response, 'context_data'))
    195         self.assertFalse(hasattr(unpickled_response, '_post_render_callbacks'))
     194        template_attrs = ('template_name', 'context_data', '_post_render_callbacks')
     195        for attr in template_attrs:
     196            self.assertFalse(hasattr(unpickled_response, attr))
     197
     198        # ...and requesting any of those attributes raises an exception
     199        for attr in template_attrs:
     200            with self.assertRaises(DiscardedAttributeError) as cm:
     201                getattr(unpickled_response, attr)
     202
     203    def test_repickling(self):
     204        response = SimpleTemplateResponse('first/test.html', {
     205                'value': 123,
     206                'fn': datetime.now,
     207            })
     208        self.assertRaises(ContentNotRenderedError,
     209                          pickle.dumps, response)
     210
     211        response.render()
     212        pickled_response = pickle.dumps(response)
     213        unpickled_response = pickle.loads(pickled_response)
     214        repickled_response = pickle.dumps(unpickled_response)
    196215
    197216class TemplateResponseTest(BaseTemplateResponseTest):
    198217
    class TemplateResponseTest(BaseTemplateResponseTest): 
    255274
    256275        # ...and the unpickled reponse doesn't have the
    257276        # template-related attributes, so it can't be re-rendered
    258         self.assertFalse(hasattr(unpickled_response, '_request'))
    259         self.assertFalse(hasattr(unpickled_response, 'template_name'))
    260         self.assertFalse(hasattr(unpickled_response, 'context_data'))
    261         self.assertFalse(hasattr(unpickled_response, '_post_render_callbacks'))
     277        template_attrs = ('template_name', 'context_data',
     278            '_post_render_callbacks', '_request', '_current_app')
     279        for attr in template_attrs:
     280            self.assertFalse(hasattr(unpickled_response, attr))
     281
     282        # ...and requesting any of those attributes raises an exception
     283        for attr in template_attrs:
     284            with self.assertRaises(DiscardedAttributeError) as cm:
     285                getattr(unpickled_response, attr)
     286
     287    def test_repickling(self):
     288        response = SimpleTemplateResponse('first/test.html', {
     289                'value': 123,
     290                'fn': datetime.now,
     291            })
     292        self.assertRaises(ContentNotRenderedError,
     293                          pickle.dumps, response)
     294
     295        response.render()
     296        pickled_response = pickle.dumps(response)
     297        unpickled_response = pickle.loads(pickled_response)
     298        repickled_response = pickle.dumps(unpickled_response)
    262299
    263300
    264301class CustomURLConfTest(TestCase):
Back to Top