diff -r 9b484f4bd7e0 django/middleware/cache.py
a
|
b
|
|
50 | 50 | |
51 | 51 | from django.conf import settings |
52 | 52 | from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS |
| 53 | from django.http import HttpResponse |
53 | 54 | from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age |
54 | 55 | |
| 56 | def cache_templateresponse_cb(cache_obj, cache_key, timeout): |
| 57 | """Callback for TemplateResponse objects to cache a plain HttpResponse |
| 58 | object upon rendering.""" |
| 59 | def __callback__(response): |
| 60 | plain_response = HttpResponse() |
| 61 | for attr in ['status_code', '_headers', '_charset', '_container', |
| 62 | '_is_string', 'cookies']: |
| 63 | setattr(plain_response, attr, getattr(response, attr)) |
| 64 | cache_obj.set(cache_key, plain_response, timeout) |
| 65 | return plain_response |
| 66 | return __callback__ |
| 67 | |
55 | 68 | class UpdateCacheMiddleware(object): |
56 | 69 | """ |
57 | 70 | Response-phase cache middleware that updates the cache if the response is |
… |
… |
|
86 | 99 | patch_response_headers(response, timeout) |
87 | 100 | if timeout: |
88 | 101 | cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) |
89 | | self.cache.set(cache_key, response, timeout) |
| 102 | if hasattr(response, 'render') and callable(response.render): |
| 103 | response.post_render_callback = cache_templateresponse_cb( |
| 104 | self.cache, cache_key, timeout) |
| 105 | else: |
| 106 | self.cache.set(cache_key, response, timeout) |
90 | 107 | return response |
91 | 108 | |
92 | 109 | class FetchFromCacheMiddleware(object): |
diff -r 9b484f4bd7e0 django/template/response.py
a
|
b
|
|
65 | 65 | Returns the baked response instance. |
66 | 66 | """ |
67 | 67 | if not self._is_rendered: |
| 68 | if callable(self.pre_render_callback): |
| 69 | self.pre_render_callback(self) |
68 | 70 | self._set_content(self.rendered_content) |
| 71 | if callable(self.post_render_callback): |
| 72 | self.post_render_callback(self) |
69 | 73 | return self |
70 | 74 | |
71 | 75 | is_rendered = property(lambda self: self._is_rendered) |
72 | 76 | |
| 77 | pre_render_callback = None |
| 78 | post_render_callback = None |
| 79 | |
73 | 80 | def __iter__(self): |
74 | 81 | if not self._is_rendered: |
75 | 82 | raise ContentNotRenderedError('The response content must be rendered before it can be iterated over.') |
… |
… |
|
109 | 116 | return context |
110 | 117 | else: |
111 | 118 | return RequestContext(self._request, context, current_app=self._current_app) |
| 119 | |
| 120 | |
diff -r 9b484f4bd7e0 tests/regressiontests/generic_views/base.py
a
|
b
|
|
| 1 | import time |
1 | 2 | import unittest |
2 | 3 | |
3 | 4 | from django.core.exceptions import ImproperlyConfigured |
… |
… |
|
158 | 159 | def _assert_about(self, response): |
159 | 160 | response.render() |
160 | 161 | self.assertEqual(response.status_code, 200) |
161 | | self.assertEqual(response.content, '<h1>About</h1>') |
| 162 | self.assertContains(response, '<h1>About</h1>') |
162 | 163 | |
163 | 164 | def test_get(self): |
164 | 165 | """ |
… |
… |
|
197 | 198 | self.assertEqual(response.context['params'], {'foo': 'bar'}) |
198 | 199 | self.assertEqual(response.context['key'], 'value') |
199 | 200 | |
| 201 | def test_cached_views(self): |
| 202 | """ |
| 203 | A template view can be cached |
| 204 | """ |
| 205 | response = self.client.get('/template/cached/bar/') |
| 206 | self.assertEqual(response.status_code, 200) |
| 207 | |
| 208 | time.sleep(0.2) |
| 209 | |
| 210 | response2 = self.client.get('/template/cached/bar/') |
| 211 | self.assertEqual(response2.status_code, 200) |
| 212 | |
| 213 | self.assertEqual(response.content, response2.content) |
| 214 | |
| 215 | time.sleep(1.0) |
| 216 | |
| 217 | # Let the cache expire and test again |
| 218 | response2 = self.client.get('/template/cached/bar/') |
| 219 | self.assertEqual(response2.status_code, 200) |
| 220 | |
| 221 | self.assertNotEqual(response.content, response2.content) |
| 222 | |
200 | 223 | class RedirectViewTest(unittest.TestCase): |
201 | 224 | rf = RequestFactory() |
202 | 225 | |
diff -r 9b484f4bd7e0 tests/regressiontests/generic_views/templates/generic_views/about.html
a
|
b
|
|
1 | | <h1>About</h1> |
2 | | No newline at end of file |
| 1 | <h1>About</h1> |
| 2 | {% now "U.u" %} |
diff -r 9b484f4bd7e0 tests/regressiontests/generic_views/urls.py
a
|
b
|
|
1 | 1 | from django.conf.urls.defaults import * |
2 | 2 | from django.views.generic import TemplateView |
| 3 | from django.views.decorators.cache import cache_page |
3 | 4 | |
4 | 5 | import views |
5 | 6 | |
… |
… |
|
15 | 16 | (r'^template/custom/(?P<foo>\w+)/$', |
16 | 17 | views.CustomTemplateView.as_view(template_name='generic_views/about.html')), |
17 | 18 | |
| 19 | (r'^template/cached/(?P<foo>\w+)/$', |
| 20 | cache_page(TemplateView.as_view(template_name='generic_views/about.html'), 1)), |
| 21 | |
18 | 22 | # DetailView |
19 | 23 | (r'^detail/obj/$', |
20 | 24 | views.ObjectDetail.as_view()), |