diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2011-01-24 14:24:35 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2011-01-24 14:24:35 +0000 |
| commit | 3f528e10d50ff7ba19a8a9e6cb2f9417a1e7f270 (patch) | |
| tree | d99a22a125586c1f932171a1c78c1daf5b0e6371 /tests | |
| parent | 3d7afd5d2b64546cdcfd812d2cecb61795e788f0 (diff) | |
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
Diffstat (limited to 'tests')
6 files changed, 144 insertions, 5 deletions
diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py index f356c90a74..c378315b62 100644 --- a/tests/regressiontests/generic_views/base.py +++ b/tests/regressiontests/generic_views/base.py @@ -1,3 +1,4 @@ +import time import unittest from django.core.exceptions import ImproperlyConfigured @@ -158,7 +159,7 @@ class TemplateViewTest(TestCase): def _assert_about(self, response): response.render() self.assertEqual(response.status_code, 200) - self.assertEqual(response.content, '<h1>About</h1>') + self.assertContains(response, '<h1>About</h1>') def test_get(self): """ @@ -197,6 +198,28 @@ class TemplateViewTest(TestCase): self.assertEqual(response.context['params'], {'foo': 'bar'}) self.assertEqual(response.context['key'], 'value') + def test_cached_views(self): + """ + A template view can be cached + """ + response = self.client.get('/template/cached/bar/') + self.assertEqual(response.status_code, 200) + + time.sleep(1.0) + + response2 = self.client.get('/template/cached/bar/') + self.assertEqual(response2.status_code, 200) + + self.assertEqual(response.content, response2.content) + + time.sleep(2.0) + + # Let the cache expire and test again + response2 = self.client.get('/template/cached/bar/') + self.assertEqual(response2.status_code, 200) + + self.assertNotEqual(response.content, response2.content) + class RedirectViewTest(unittest.TestCase): rf = RequestFactory() diff --git a/tests/regressiontests/generic_views/templates/generic_views/about.html b/tests/regressiontests/generic_views/templates/generic_views/about.html index 7d877fdd78..f946f630cf 100644 --- a/tests/regressiontests/generic_views/templates/generic_views/about.html +++ b/tests/regressiontests/generic_views/templates/generic_views/about.html @@ -1 +1,2 @@ -<h1>About</h1>
\ No newline at end of file +<h1>About</h1> +{% now "U.u" %} diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py index bd997e7e6d..4c847ac78d 100644 --- a/tests/regressiontests/generic_views/urls.py +++ b/tests/regressiontests/generic_views/urls.py @@ -1,5 +1,6 @@ from django.conf.urls.defaults import * from django.views.generic import TemplateView +from django.views.decorators.cache import cache_page import views @@ -15,6 +16,9 @@ urlpatterns = patterns('', (r'^template/custom/(?P<foo>\w+)/$', views.CustomTemplateView.as_view(template_name='generic_views/about.html')), + (r'^template/cached/(?P<foo>\w+)/$', + cache_page(2.0)(TemplateView.as_view(template_name='generic_views/about.html'))), + # DetailView (r'^detail/obj/$', views.ObjectDetail.as_view()), diff --git a/tests/regressiontests/templates/alternate_urls.py b/tests/regressiontests/templates/alternate_urls.py index 31590a5dbc..e68f1c5875 100644 --- a/tests/regressiontests/templates/alternate_urls.py +++ b/tests/regressiontests/templates/alternate_urls.py @@ -1,10 +1,12 @@ # coding: utf-8 from django.conf.urls.defaults import * + from regressiontests.templates import views + urlpatterns = patterns('', # View returning a template response - (r'^template_response_view/', views.template_response_view), + (r'^template_response_view/$', views.template_response_view), # A view that can be hard to find... url(r'^snark/', views.snark, name='snark'), diff --git a/tests/regressiontests/templates/response.py b/tests/regressiontests/templates/response.py index f658b35ac3..1e42d66663 100644 --- a/tests/regressiontests/templates/response.py +++ b/tests/regressiontests/templates/response.py @@ -1,4 +1,7 @@ +from datetime import datetime import os +import pickle +import time from django.utils import unittest from django.test import RequestFactory, TestCase from django.conf import settings @@ -147,6 +150,49 @@ class SimpleTemplateResponseTest(BaseTemplateResponseTest): self.assertEqual(response['content-type'], 'application/json') self.assertEqual(response.status_code, 504) + def test_post_callbacks(self): + "Rendering a template response triggers the post-render callbacks" + post = [] + + def post1(obj): + post.append('post1') + def post2(obj): + post.append('post2') + + response = SimpleTemplateResponse('first/test.html', {}) + response.add_post_render_callback(post1) + response.add_post_render_callback(post2) + + # When the content is rendered, all the callbacks are invoked, too. + response.render() + self.assertEqual('First template\n', response.content) + self.assertEquals(post, ['post1','post2']) + + + def test_pickling(self): + # Create a template response. The context is + # known to be unpickleable (e.g., a function). + response = SimpleTemplateResponse('first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + # But if we render the response, we can pickle it. + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + + self.assertEquals(unpickled_response.content, response.content) + self.assertEquals(unpickled_response['content-type'], response['content-type']) + self.assertEquals(unpickled_response.status_code, response.status_code) + + # ...and the unpickled reponse doesn't have the + # template-related attributes, so it can't be re-rendered + self.assertFalse(hasattr(unpickled_response, 'template_name')) + self.assertFalse(hasattr(unpickled_response, 'context_data')) + self.assertFalse(hasattr(unpickled_response, '_post_render_callbacks')) class TemplateResponseTest(BaseTemplateResponseTest): @@ -187,6 +233,33 @@ class TemplateResponseTest(BaseTemplateResponseTest): self.assertEqual(rc.current_app, 'foobar') + def test_pickling(self): + # Create a template response. The context is + # known to be unpickleable (e.g., a function). + response = TemplateResponse(self.factory.get('/'), + 'first/test.html', { + 'value': 123, + 'fn': datetime.now, + }) + self.assertRaises(ContentNotRenderedError, + pickle.dumps, response) + + # But if we render the response, we can pickle it. + response.render() + pickled_response = pickle.dumps(response) + unpickled_response = pickle.loads(pickled_response) + + self.assertEquals(unpickled_response.content, response.content) + self.assertEquals(unpickled_response['content-type'], response['content-type']) + self.assertEquals(unpickled_response.status_code, response.status_code) + + # ...and the unpickled reponse doesn't have the + # template-related attributes, so it can't be re-rendered + self.assertFalse(hasattr(unpickled_response, '_request')) + self.assertFalse(hasattr(unpickled_response, 'template_name')) + self.assertFalse(hasattr(unpickled_response, 'context_data')) + self.assertFalse(hasattr(unpickled_response, '_post_render_callbacks')) + class CustomURLConfTest(TestCase): urls = 'regressiontests.templates.urls' @@ -203,6 +276,41 @@ class CustomURLConfTest(TestCase): def test_custom_urlconf(self): response = self.client.get('/template_response_view/') self.assertEqual(response.status_code, 200) - self.assertEqual(response.content, 'This is where you can find the snark: /snark/') + self.assertContains(response, 'This is where you can find the snark: /snark/') + + +class CacheMiddlewareTest(TestCase): + urls = 'regressiontests.templates.alternate_urls' + + def setUp(self): + self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES + self.CACHE_MIDDLEWARE_SECONDS = settings.CACHE_MIDDLEWARE_SECONDS + + settings.CACHE_MIDDLEWARE_SECONDS = 2.0 + settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ + 'django.middleware.cache.FetchFromCacheMiddleware', + 'django.middleware.cache.UpdateCacheMiddleware', + ] + + def tearDown(self): + settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES + settings.CACHE_MIDDLEWARE_SECONDS = self.CACHE_MIDDLEWARE_SECONDS + + def test_middleware_caching(self): + response = self.client.get('/template_response_view/') + self.assertEqual(response.status_code, 200) + + time.sleep(1.0) + + response2 = self.client.get('/template_response_view/') + self.assertEqual(response2.status_code, 200) + + self.assertEqual(response.content, response2.content) + + time.sleep(2.0) + # Let the cache expire and test again + response2 = self.client.get('/template_response_view/') + self.assertEqual(response2.status_code, 200) + self.assertNotEqual(response.content, response2.content) diff --git a/tests/regressiontests/templates/templates/response.html b/tests/regressiontests/templates/templates/response.html index 7c442fb453..7535fa7606 100644 --- a/tests/regressiontests/templates/templates/response.html +++ b/tests/regressiontests/templates/templates/response.html @@ -1 +1,2 @@ -{% load url from future %}This is where you can find the snark: {% url "snark" %}
\ No newline at end of file +{% load url from future %}This is where you can find the snark: {% url "snark" %} +{% now "U.u" %}
\ No newline at end of file |
