Ticket #16326: ticket16326.diff

File ticket16326.diff, 6.5 KB (added by Łukasz Rekucki, 13 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..12a3e4e 100644
    a b  
     1from __future__ import with_statement
    12from datetime import datetime
    23import os
    34import pickle
    from django.conf import settings  
    89import django.template.context
    910from django.template import Template, Context, RequestContext
    1011from django.template.response import (TemplateResponse, SimpleTemplateResponse,
    11                                       ContentNotRenderedError)
     12                                      ContentNotRenderedError,
     13                                      DiscardedAttributeError)
    1214
    1315def test_processor(request):
    1416    return {'processors': 'yes'}
    class SimpleTemplateResponseTest(BaseTemplateResponseTest):  
    190192
    191193        # ...and the unpickled reponse doesn't have the
    192194        # 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'))
     195        template_attrs = ('template_name', 'context_data', '_post_render_callbacks')
     196        for attr in template_attrs:
     197            self.assertFalse(hasattr(unpickled_response, attr))
     198
     199        # ...and requesting any of those attributes raises an exception
     200        for attr in template_attrs:
     201            with self.assertRaises(DiscardedAttributeError) as cm:
     202                getattr(unpickled_response, attr)
     203
     204    def test_repickling(self):
     205        response = SimpleTemplateResponse('first/test.html', {
     206                'value': 123,
     207                'fn': datetime.now,
     208            })
     209        self.assertRaises(ContentNotRenderedError,
     210                          pickle.dumps, response)
     211
     212        response.render()
     213        pickled_response = pickle.dumps(response)
     214        unpickled_response = pickle.loads(pickled_response)
     215        repickled_response = pickle.dumps(unpickled_response)
    196216
    197217class TemplateResponseTest(BaseTemplateResponseTest):
    198218
    class TemplateResponseTest(BaseTemplateResponseTest):  
    255275
    256276        # ...and the unpickled reponse doesn't have the
    257277        # 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'))
     278        template_attrs = ('template_name', 'context_data',
     279            '_post_render_callbacks', '_request', '_current_app')
     280        for attr in template_attrs:
     281            self.assertFalse(hasattr(unpickled_response, attr))
     282
     283        # ...and requesting any of those attributes raises an exception
     284        for attr in template_attrs:
     285            with self.assertRaises(DiscardedAttributeError) as cm:
     286                getattr(unpickled_response, attr)
     287
     288    def test_repickling(self):
     289        response = SimpleTemplateResponse('first/test.html', {
     290                'value': 123,
     291                'fn': datetime.now,
     292            })
     293        self.assertRaises(ContentNotRenderedError,
     294                          pickle.dumps, response)
     295
     296        response.render()
     297        pickled_response = pickle.dumps(response)
     298        unpickled_response = pickle.loads(pickled_response)
     299        repickled_response = pickle.dumps(unpickled_response)
    262300
    263301
    264302class CustomURLConfTest(TestCase):
Back to Top