1 from __future__
import with_statement
6 from datetime
import datetime
8 from django
.utils
import unittest
9 from django
.test
import RequestFactory
, TestCase
10 from django
.conf
import settings
11 import django
.template
.context
12 from django
.template
import Template
, Context
13 from django
.template
.response
import (TemplateResponse
, SimpleTemplateResponse
,
14 ContentNotRenderedError
)
16 def test_processor(request
):
17 return {'processors': 'yes'}
18 test_processor_name
= 'regressiontests.templates.response.test_processor'
21 # A test middleware that installs a temporary URLConf
22 class CustomURLConfMiddleware(object):
23 def process_request(self
, request
):
24 request
.urlconf
= 'regressiontests.templates.alternate_urls'
27 class BaseTemplateResponseTest(unittest
.TestCase
):
28 # tests rely on fact that global context
29 # processors should only work when RequestContext is used.
32 self
.factory
= RequestFactory()
33 self
._old
_processors
= settings
.TEMPLATE_CONTEXT_PROCESSORS
34 self
._old
_TEMPLATE
_DIRS
= settings
.TEMPLATE_DIRS
35 settings
.TEMPLATE_CONTEXT_PROCESSORS
= [test_processor_name
]
36 settings
.TEMPLATE_DIRS
= (
38 os
.path
.dirname(__file__
),
42 # Force re-evaluation of the contex processor list
43 django
.template
.context
._standard
_context
_processors
= None
46 settings
.TEMPLATE_DIRS
= self
._old
_TEMPLATE
_DIRS
47 settings
.TEMPLATE_CONTEXT_PROCESSORS
= self
._old
_processors
48 # Force re-evaluation of the contex processor list
49 django
.template
.context
._standard
_context
_processors
= None
52 class SimpleTemplateResponseTest(BaseTemplateResponseTest
):
54 def _response(self
, template
='foo', *args
, **kwargs
):
55 return SimpleTemplateResponse(Template(template
), *args
, **kwargs
)
57 def test_template_resolving(self
):
58 response
= SimpleTemplateResponse('first/test.html')
60 self
.assertEqual('First template\n', response
.content
)
62 templates
= ['foo.html', 'second/test.html', 'first/test.html']
63 response
= SimpleTemplateResponse(templates
)
65 self
.assertEqual('Second template\n', response
.content
)
67 response
= self
._response
()
69 self
.assertEqual(response
.content
, 'foo')
71 def test_explicit_baking(self
):
73 response
= self
._response
()
74 self
.assertFalse(response
.is_rendered
)
76 self
.assertTrue(response
.is_rendered
)
78 def test_render(self
):
79 # response is not re-rendered without the render call
80 response
= self
._response
().render()
81 self
.assertEqual(response
.content
, 'foo')
83 # rebaking doesn't change the rendered content
84 response
.template_name
= Template('bar{{ baz }}')
86 self
.assertEqual(response
.content
, 'foo')
88 # but rendered content can be overridden by manually
90 response
.content
= 'bar'
91 self
.assertEqual(response
.content
, 'bar')
93 def test_iteration_unrendered(self
):
94 # unrendered response raises an exception on iteration
95 response
= self
._response
()
96 self
.assertFalse(response
.is_rendered
)
101 self
.assertRaises(ContentNotRenderedError
, iteration
)
102 self
.assertFalse(response
.is_rendered
)
104 def test_iteration_rendered(self
):
105 # iteration works for rendered responses
106 response
= self
._response
().render()
107 res
= [x
for x
in response
]
108 self
.assertEqual(res
, ['foo'])
110 def test_content_access_unrendered(self
):
111 # unrendered response raises an exception when content is accessed
112 response
= self
._response
()
113 self
.assertFalse(response
.is_rendered
)
114 self
.assertRaises(ContentNotRenderedError
, lambda: response
.content
)
115 self
.assertFalse(response
.is_rendered
)
117 def test_content_access_rendered(self
):
118 # rendered response content can be accessed
119 response
= self
._response
().render()
120 self
.assertEqual(response
.content
, 'foo')
122 def test_set_content(self
):
123 # content can be overriden
124 response
= self
._response
()
125 self
.assertFalse(response
.is_rendered
)
126 response
.content
= 'spam'
127 self
.assertTrue(response
.is_rendered
)
128 self
.assertEqual(response
.content
, 'spam')
129 response
.content
= 'baz'
130 self
.assertEqual(response
.content
, 'baz')
132 def test_dict_context(self
):
133 response
= self
._response
('{{ foo }}{{ processors }}',
135 self
.assertEqual(response
.context_data
, {'foo': 'bar'})
137 self
.assertEqual(response
.content
, 'bar')
139 def test_context_instance(self
):
140 response
= self
._response
('{{ foo }}{{ processors }}',
141 Context({'foo': 'bar'}))
142 self
.assertEqual(response
.context_data
.__class
__, Context
)
144 self
.assertEqual(response
.content
, 'bar')
146 def test_kwargs(self
):
147 response
= self
._response
(content_type
= 'application/json', status
=504)
148 self
.assertEqual(response
['content-type'], 'application/json')
149 self
.assertEqual(response
.status_code
, 504)
152 response
= SimpleTemplateResponse('', {}, 'application/json', 504)
153 self
.assertEqual(response
['content-type'], 'application/json')
154 self
.assertEqual(response
.status_code
, 504)
156 def test_post_callbacks(self
):
157 "Rendering a template response triggers the post-render callbacks"
165 response
= SimpleTemplateResponse('first/test.html', {})
166 response
.add_post_render_callback(post1
)
167 response
.add_post_render_callback(post2
)
169 # When the content is rendered, all the callbacks are invoked, too.
171 self
.assertEqual('First template\n', response
.content
)
172 self
.assertEqual(post
, ['post1','post2'])
175 def test_pickling(self
):
176 # Create a template response. The context is
177 # known to be unpickleable (e.g., a function).
178 response
= SimpleTemplateResponse('first/test.html', {
182 self
.assertRaises(ContentNotRenderedError
,
183 pickle
.dumps
, response
)
185 # But if we render the response, we can pickle it.
187 pickled_response
= pickle
.dumps(response
)
188 unpickled_response
= pickle
.loads(pickled_response
)
190 self
.assertEqual(unpickled_response
.content
, response
.content
)
191 self
.assertEqual(unpickled_response
['content-type'], response
['content-type'])
192 self
.assertEqual(unpickled_response
.status_code
, response
.status_code
)
194 # ...and the unpickled reponse doesn't have the
195 # template-related attributes, so it can't be re-rendered
196 template_attrs
= ('template_name', 'context_data', '_post_render_callbacks')
197 for attr
in template_attrs
:
198 self
.assertFalse(hasattr(unpickled_response
, attr
))
200 # ...and requesting any of those attributes raises an exception
201 for attr
in template_attrs
:
202 with self
.assertRaises(AttributeError):
203 getattr(unpickled_response
, attr
)
205 def test_repickling(self
):
206 response
= SimpleTemplateResponse('first/test.html', {
210 self
.assertRaises(ContentNotRenderedError
,
211 pickle
.dumps
, response
)
214 pickled_response
= pickle
.dumps(response
)
215 unpickled_response
= pickle
.loads(pickled_response
)
216 repickled_response
= pickle
.dumps(unpickled_response
)
218 class TemplateResponseTest(BaseTemplateResponseTest
):
220 def _response(self
, template
='foo', *args
, **kwargs
):
221 return TemplateResponse(self
.factory
.get('/'), Template(template
),
224 def test_render(self
):
225 response
= self
._response
('{{ foo }}{{ processors }}').render()
226 self
.assertEqual(response
.content
, 'yes')
228 def test_render_with_requestcontext(self
):
229 response
= self
._response
('{{ foo }}{{ processors }}',
230 {'foo': 'bar'}).render()
231 self
.assertEqual(response
.content
, 'baryes')
233 def test_render_with_context(self
):
234 response
= self
._response
('{{ foo }}{{ processors }}',
235 Context({'foo': 'bar'})).render()
236 self
.assertEqual(response
.content
, 'bar')
238 def test_kwargs(self
):
239 response
= self
._response
(content_type
= 'application/json',
241 self
.assertEqual(response
['content-type'], 'application/json')
242 self
.assertEqual(response
.status_code
, 504)
245 response
= TemplateResponse(self
.factory
.get('/'), '', {},
246 'application/json', 504)
247 self
.assertEqual(response
['content-type'], 'application/json')
248 self
.assertEqual(response
.status_code
, 504)
250 def test_custom_app(self
):
251 response
= self
._response
('{{ foo }}', current_app
="foobar")
253 rc
= response
.resolve_context(response
.context_data
)
255 self
.assertEqual(rc
.current_app
, 'foobar')
257 def test_pickling(self
):
258 # Create a template response. The context is
259 # known to be unpickleable (e.g., a function).
260 response
= TemplateResponse(self
.factory
.get('/'),
265 self
.assertRaises(ContentNotRenderedError
,
266 pickle
.dumps
, response
)
268 # But if we render the response, we can pickle it.
270 pickled_response
= pickle
.dumps(response
)
271 unpickled_response
= pickle
.loads(pickled_response
)
273 self
.assertEqual(unpickled_response
.content
, response
.content
)
274 self
.assertEqual(unpickled_response
['content-type'], response
['content-type'])
275 self
.assertEqual(unpickled_response
.status_code
, response
.status_code
)
277 # ...and the unpickled reponse doesn't have the
278 # template-related attributes, so it can't be re-rendered
279 template_attrs
= ('template_name', 'context_data',
280 '_post_render_callbacks', '_request', '_current_app')
281 for attr
in template_attrs
:
282 self
.assertFalse(hasattr(unpickled_response
, attr
))
284 # ...and requesting any of those attributes raises an exception
285 for attr
in template_attrs
:
286 with self
.assertRaises(AttributeError):
287 getattr(unpickled_response
, attr
)
289 def test_repickling(self
):
290 response
= SimpleTemplateResponse('first/test.html', {
294 self
.assertRaises(ContentNotRenderedError
,
295 pickle
.dumps
, response
)
298 pickled_response
= pickle
.dumps(response
)
299 unpickled_response
= pickle
.loads(pickled_response
)
300 repickled_response
= pickle
.dumps(unpickled_response
)
303 class CustomURLConfTest(TestCase
):
304 urls
= 'regressiontests.templates.urls'
307 self
.old_MIDDLEWARE_CLASSES
= settings
.MIDDLEWARE_CLASSES
308 settings
.MIDDLEWARE_CLASSES
= list(settings
.MIDDLEWARE_CLASSES
) + [
309 'regressiontests.templates.response.CustomURLConfMiddleware'
313 settings
.MIDDLEWARE_CLASSES
= self
.old_MIDDLEWARE_CLASSES
315 def test_custom_urlconf(self
):
316 response
= self
.client
.get('/template_response_view/')
317 self
.assertEqual(response
.status_code
, 200)
318 self
.assertContains(response
, 'This is where you can find the snark: /snark/')
321 class CacheMiddlewareTest(TestCase
):
322 urls
= 'regressiontests.templates.alternate_urls'
325 self
.old_MIDDLEWARE_CLASSES
= settings
.MIDDLEWARE_CLASSES
326 self
.CACHE_MIDDLEWARE_SECONDS
= settings
.CACHE_MIDDLEWARE_SECONDS
328 settings
.CACHE_MIDDLEWARE_SECONDS
= 2.0
329 settings
.MIDDLEWARE_CLASSES
= list(settings
.MIDDLEWARE_CLASSES
) + [
330 'django.middleware.cache.FetchFromCacheMiddleware',
331 'django.middleware.cache.UpdateCacheMiddleware',
335 settings
.MIDDLEWARE_CLASSES
= self
.old_MIDDLEWARE_CLASSES
336 settings
.CACHE_MIDDLEWARE_SECONDS
= self
.CACHE_MIDDLEWARE_SECONDS
338 def test_middleware_caching(self
):
339 response
= self
.client
.get('/template_response_view/')
340 self
.assertEqual(response
.status_code
, 200)
344 response2
= self
.client
.get('/template_response_view/')
345 self
.assertEqual(response2
.status_code
, 200)
347 self
.assertEqual(response
.content
, response2
.content
)
351 # Let the cache expire and test again
352 response2
= self
.client
.get('/template_response_view/')
353 self
.assertEqual(response2
.status_code
, 200)
355 self
.assertNotEqual(response
.content
, response2
.content
)