Ticket #12816: render_shortcut.5.diff
File render_shortcut.5.diff, 22.0 KB (added by , 14 years ago) |
---|
-
django/contrib/messages/middleware.py
diff -r c67d03486d14 django/contrib/messages/middleware.py
a b 20 20 # A higher middleware layer may return a request which does not contain 21 21 # messages storage, so make no assumption that it will be there. 22 22 if hasattr(request, '_messages'): 23 24 # we have to bake the response here because there is no way to 25 # determine if messages where iterated in template or not 26 if hasattr(response, 'bake') and callable(response.bake): 27 response.bake() 28 23 29 unstored_messages = request._messages.update(response) 24 30 if unstored_messages and settings.DEBUG: 25 31 raise ValueError('Not all temporary messages could be stored.') -
django/contrib/messages/tests/base.py
diff -r c67d03486d14 django/contrib/messages/tests/base.py
a b 96 96 storage = self.get_storage() 97 97 self.assertFalse(storage.added_new) 98 98 storage.add(constants.INFO, 'Test message 1') 99 self.assert _(storage.added_new)99 self.assertTrue(storage.added_new) 100 100 storage.add(constants.INFO, 'Test message 2', extra_tags='tag') 101 101 self.assertEqual(len(storage), 2) 102 102 … … 173 173 for msg in data['messages']: 174 174 self.assertContains(response, msg) 175 175 176 def test_with_template_response(self): 177 settings.MESSAGE_LEVEL = constants.DEBUG 178 data = { 179 'messages': ['Test message %d' % x for x in xrange(10)], 180 } 181 show_url = reverse(self.urls + '.show_template_response') 182 183 for level in self.levels.keys(): 184 add_url = reverse(self.urls + '.add_template_response', 185 args=(level,)) 186 response = self.client.post(add_url, data, follow=True) 187 self.assertRedirects(response, show_url) 188 self.assertTrue('messages' in response.context) 189 for msg in data['messages']: 190 self.assertContains(response, msg) 191 192 # there shouldn't be any messages on second GET request 193 response = self.client.get(show_url) 194 for msg in data['messages']: 195 self.assertNotContains(response, msg) 196 176 197 def test_multiple_posts(self): 177 198 """ 178 199 Tests that messages persist properly when multiple POSTs are made -
django/contrib/messages/tests/urls.py
diff -r c67d03486d14 django/contrib/messages/tests/urls.py
a b 2 2 from django.contrib import messages 3 3 from django.core.urlresolvers import reverse 4 4 from django.http import HttpResponseRedirect, HttpResponse 5 from django.shortcuts import render_to_response 5 from django.shortcuts import render_to_response, redirect 6 6 from django.template import RequestContext, Template 7 from django.template.response import TemplateResponse 7 8 9 TEMPLATE = """{% if messages %} 10 <ul class="messages"> 11 {% for message in messages %} 12 <li{% if message.tags %} class="{{ message.tags }}"{% endif %}> 13 {{ message }} 14 </li> 15 {% endfor %} 16 </ul> 17 {% endif %} 18 """ 8 19 9 20 def add(request, message_type): 10 21 # don't default to False here, because we want to test that it defaults … … 16 27 fail_silently=fail_silently) 17 28 else: 18 29 getattr(messages, message_type)(request, msg) 30 19 31 show_url = reverse('django.contrib.messages.tests.urls.show') 20 32 return HttpResponseRedirect(show_url) 21 33 34 def add_template_response(request, message_type): 35 for msg in request.POST.getlist('messages'): 36 getattr(messages, message_type)(request, msg) 37 return redirect('django.contrib.messages.tests.urls.show_template_response') 22 38 23 39 def show(request): 24 t = Template("""{% if messages %} 25 <ul class="messages"> 26 {% for message in messages %} 27 <li{% if message.tags %} class="{{ message.tags }}"{% endif %}> 28 {{ message }} 29 </li> 30 {% endfor %} 31 </ul> 32 {% endif %}""") 40 t = Template(TEMPLATE) 33 41 return HttpResponse(t.render(RequestContext(request))) 34 42 43 def show_template_response(request): 44 return TemplateResponse(request, Template(TEMPLATE)) 35 45 36 46 urlpatterns = patterns('', 37 47 ('^add/(debug|info|success|warning|error)/$', add), 38 48 ('^show/$', show), 49 ('^add-template-response/(debug|info|success|warning|error)/$', add_template_response), 50 ('^show-template-response/$', show_template_response), 39 51 ) -
django/shortcuts/__init__.py
diff -r c67d03486d14 django/shortcuts/__init__.py
a b 5 5 """ 6 6 7 7 from django.template import loader 8 from django.template.response import TemplateResponse 8 9 from django.http import HttpResponse, Http404 9 10 from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect 10 11 from django.db.models.manager import Manager … … 23 24 """ 24 25 Returns an HttpResponseRedirect to the apropriate URL for the arguments 25 26 passed. 26 27 27 28 The arguments could be: 28 29 29 30 * A model: the model's `get_absolute_url()` function will be called. 30 31 31 32 * A view name, possibly with arguments: `urlresolvers.reverse()` will 32 33 be used to reverse-resolve the name. 33 34 34 35 * A URL, which will be used as-is for the redirect location. 35 36 36 37 By default issues a temporary redirect; pass permanent=True to issue a 37 38 permanent redirect 38 39 """ … … 40 41 redirect_class = HttpResponsePermanentRedirect 41 42 else: 42 43 redirect_class = HttpResponseRedirect 43 44 44 45 # If it's a model, use get_absolute_url() 45 46 if hasattr(to, 'get_absolute_url'): 46 47 return redirect_class(to.get_absolute_url()) 47 48 48 49 # Next try a reverse URL resolution. 49 50 try: 50 51 return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs)) … … 55 56 # If this doesn't "feel" like a URL, re-raise. 56 57 if '/' not in to and '.' not in to: 57 58 raise 58 59 59 60 # Finally, fall back and assume it's a URL 60 61 return redirect_class(to) 61 62 … … 101 102 obj_list = list(queryset.filter(*args, **kwargs)) 102 103 if not obj_list: 103 104 raise Http404('No %s matches the given query.' % queryset.model._meta.object_name) 104 return obj_list 105 No newline at end of file 105 return obj_list 106 107 render = TemplateResponse -
new file django/template/response.py
diff -r c67d03486d14 django/template/response.py
- + 1 from django.http import HttpResponse 2 from django.template import loader, Context, RequestContext 3 4 class SimpleTemplateResponse(HttpResponse): 5 6 def __init__(self, template, context=None, mimetype=None, status=None, 7 content_type=None): 8 # These two properties were originally called 'template' and 'context' 9 # but django.test.client.Client was clobbering those leading to really 10 # tricky-to-debug problems 11 self.template_name = template 12 self.template_context = context 13 self.baked = False 14 15 # content argument doesn't make sense here because it will be replaced 16 # with rendered template so we always pass empty string in order to 17 # prevent errors and provide shorter signature. 18 super(SimpleTemplateResponse, self).__init__('', mimetype, status, 19 content_type) 20 21 def resolve_template(self, template): 22 "Accepts a template object, path-to-template or list of paths" 23 if isinstance(template, (list, tuple)): 24 return loader.select_template(template) 25 elif isinstance(template, basestring): 26 return loader.get_template(template) 27 else: 28 return template 29 30 def resolve_context(self, context): 31 "context can be a dictionary or a context object" 32 if isinstance(context, Context): 33 return context 34 else: 35 return Context(context) 36 37 def render(self): 38 template = self.resolve_template(self.template_name) 39 context = self.resolve_context(self.template_context) 40 content = template.render(context) 41 return content 42 43 def bake(self): 44 """ 45 The template is baked the first time you try to access 46 response.content or iterate over it. This is a bit ugly, but is 47 necessary because Django middleware sometimes expects to be able to 48 over-write the content of a response. 49 """ 50 if not self.baked: 51 self.force_bake() 52 53 def force_bake(self): 54 "Call this if you have modified the template or context but are " 55 "unsure if the template has already been baked." 56 self._set_content(self.render()) 57 58 def __iter__(self): 59 self.bake() 60 return super(SimpleTemplateResponse, self).__iter__() 61 62 def _get_content(self): 63 self.bake() 64 return super(SimpleTemplateResponse, self)._get_content() 65 66 def _set_content(self, value): 67 "Overrides rendered content, unless you later call force_bake()" 68 super(SimpleTemplateResponse, self)._set_content(value) 69 self.baked = True 70 71 content = property(_get_content, _set_content) 72 73 class TemplateResponse(SimpleTemplateResponse): 74 75 def __init__(self, request, template, context=None, mimetype=None, 76 status=None, content_type=None): 77 # self.request gets over-written by django.test.client.Client - and 78 # unlike template_context and template_name the _request should not 79 # be considered part of the public API. 80 self._request = request 81 super(TemplateResponse, self).__init__( 82 template, context, mimetype, status, content_type) 83 84 def resolve_context(self, context): 85 if isinstance(context, Context): 86 return context 87 else: 88 return RequestContext(self._request, context) 89 -
django/test/client.py
diff -r c67d03486d14 django/test/client.py
a b 379 379 380 380 try: 381 381 response = self.handler(environ) 382 if hasattr(response, 'bake') and callable(response.bake): 383 response.bake() 384 382 385 except TemplateDoesNotExist, e: 383 386 # If the view raises an exception, Django will attempt to show 384 387 # the 500.html template. If that template is not available, -
django/test/testcases.py
diff -r c67d03486d14 django/test/testcases.py
a b 473 473 Asserts that the template with the provided name was used in rendering 474 474 the response. 475 475 """ 476 if hasattr(response, 'bake') and callable(response.bake): 477 response.bake() 478 476 479 if msg_prefix: 477 480 msg_prefix += ": " 478 481 -
django/views/generic/base.py
diff -r c67d03486d14 django/views/generic/base.py
a b 2 2 from django import http 3 3 from django.core.exceptions import ImproperlyConfigured 4 4 from django.template import RequestContext, loader 5 from django.template.response import SimpleTemplateResponse 5 6 from django.utils.translation import ugettext_lazy as _ 6 7 from django.utils.functional import update_wrapper 7 8 from django.utils.log import getLogger … … 89 90 """ 90 91 template_name = None 91 92 92 def render_to_response(self, context ):93 def render_to_response(self, context, **httpresponse_kwargs): 93 94 """ 94 95 Returns a response with a template rendered with the given context. 95 96 """ 96 return self.get_response(self.render_template(context)) 97 98 def get_response(self, content, **httpresponse_kwargs): 99 """ 100 Construct an `HttpResponse` object. 101 """ 102 return http.HttpResponse(content, **httpresponse_kwargs) 103 104 def render_template(self, context): 105 """ 106 Render the template with a given context. 107 """ 108 context_instance = self.get_context_instance(context) 109 return self.get_template().render(context_instance) 97 return SimpleTemplateResponse( 98 self.get_template(), 99 self.get_context_instance(context), 100 **httpresponse_kwargs 101 ) 110 102 111 103 def get_context_instance(self, context): 112 104 """ -
new file tests/regressiontests/templates/response.py
diff -r c67d03486d14 tests/regressiontests/templates/response.py
- + 1 import os 2 from django.utils import unittest 3 from django.test import RequestFactory 4 from django.conf import settings 5 from django.template import Template, Context, RequestContext 6 from django.template.response import TemplateResponse, SimpleTemplateResponse 7 import django.template.context 8 9 def test_processor(request): 10 return {'processors': 'yes'} 11 test_processor_name = 'regressiontests.templates.response.test_processor' 12 13 class BaseTemplateResponseTest(unittest.TestCase): 14 # tests rely on fact that global context 15 # processors should only work when RequestContext is used. 16 17 def setUp(self): 18 self.factory = RequestFactory() 19 20 cp = list(settings.TEMPLATE_CONTEXT_PROCESSORS) 21 self._old_processors = cp[:] 22 self._old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS 23 settings.TEMPLATE_CONTEXT_PROCESSORS = cp + [test_processor_name] 24 settings.TEMPLATE_DIRS = ( 25 os.path.join( 26 os.path.dirname(__file__), 27 'templates' 28 ), 29 ) 30 31 def tearDown(self): 32 settings.TEMPLATE_DIRS = self._old_TEMPLATE_DIRS 33 settings.TEMPLATE_CONTEXT_PROCESSORS = tuple(self._old_processors) 34 # Force re-evaluation of the contex processor list 35 django.template.context._standard_context_processors = None 36 37 38 class SimpleTemplateResponseTest(BaseTemplateResponseTest): 39 40 def _response(self, template='foo', *args, **kwargs): 41 return SimpleTemplateResponse(Template(template), *args, **kwargs) 42 43 def test_template_resolving(self): 44 response = SimpleTemplateResponse('first/test.html') 45 self.assertEqual('First template\n', response.content) 46 47 templates = ['foo.html', 'second/test.html', 'first/test.html'] 48 response = SimpleTemplateResponse(templates) 49 self.assertEqual('Second template\n', response.content) 50 51 response = self._response() 52 self.assertEqual(response.content, 'foo') 53 54 def test_explicit_baking(self): 55 # explicit baking 56 response = self._response() 57 self.assertFalse(response.baked) 58 response.bake() 59 self.assertTrue(response.baked) 60 61 def test_force_bake(self): 62 # response is not re-baked without the force_bake call 63 response = self._response() 64 self.assertFalse(response.baked) 65 self.assertEqual(response.content, 'foo') 66 67 response.template_name = Template('bar{{ baz }}') 68 self.assertEqual(response.content, 'foo') 69 response.bake() 70 self.assertEqual(response.content, 'foo') 71 response.force_bake() 72 self.assertEqual(response.content, 'bar') 73 74 response.template_context = {'baz': 'baz'} 75 self.assertEqual(response.content, 'bar') 76 response.bake() 77 self.assertEqual(response.content, 'bar') 78 response.force_bake() 79 self.assertEqual(response.content, 'barbaz') 80 81 response.template_context = {'baz': 'spam'} 82 for x in response: 83 pass 84 self.assertEqual(response.content, 'barbaz') 85 86 def test_baking_on_iteration(self): 87 # response becomes baked after first iteration 88 response = self._response() 89 self.assertFalse(response.baked) 90 for x in response: 91 pass 92 self.assertTrue(response.baked) 93 94 def test_baking_on_access(self): 95 # the response is baked when content is accessed 96 response = self._response() 97 self.assertFalse(response.baked) 98 content = response.content 99 self.assertTrue(response.baked) 100 self.assertEqual(content, 'foo') 101 102 def test_set_content(self): 103 # content can be overriden 104 response = self._response() 105 self.assertFalse(response.baked) 106 response.content = 'spam' 107 self.assertTrue(response.baked) 108 self.assertEqual(response.content, 'spam') 109 response.content = 'baz' 110 self.assertEqual(response.content, 'baz') 111 112 def test_dict_context(self): 113 response = self._response('{{ foo }}{{ processors }}', 114 {'foo': 'bar'}) 115 self.assertEqual(response.template_context, {'foo': 'bar'}) 116 self.assertEqual(response.content, 'bar') 117 118 def test_context_instance(self): 119 response = self._response('{{ foo }}{{ processors }}', 120 Context({'foo': 'bar'})) 121 self.assertEqual(response.template_context.__class__, Context) 122 self.assertEqual(response.content, 'bar') 123 124 def test_kwargs(self): 125 response = self._response(content_type = 'application/json', status=504) 126 self.assertEqual(response['content-type'], 'application/json') 127 self.assertEqual(response.status_code, 504) 128 129 def test_args(self): 130 response = SimpleTemplateResponse('', {}, 'application/json', 504) 131 self.assertEqual(response['content-type'], 'application/json') 132 self.assertEqual(response.status_code, 504) 133 134 135 class TemplateResponseTest(BaseTemplateResponseTest): 136 137 def _response(self, template='foo', *args, **kwargs): 138 return TemplateResponse(self.factory.get('/'), Template(template), 139 *args, **kwargs) 140 141 def test_render(self): 142 response = self._response('{{ foo }}{{ processors }}') 143 self.assertEqual(response.content, 'yes') 144 145 def test_render_with_requestcontext(self): 146 response = self._response('{{ foo }}{{ processors }}', 147 {'foo': 'bar'}) 148 self.assertEqual(response.content, 'baryes') 149 150 def test_render_with_context(self): 151 response = self._response('{{ foo }}{{ processors }}', 152 Context({'foo': 'bar'})) 153 self.assertEqual(response.content, 'bar') 154 155 def test_kwargs(self): 156 response = self._response(content_type = 'application/json', status=504) 157 self.assertEqual(response['content-type'], 'application/json') 158 self.assertEqual(response.status_code, 504) 159 160 def test_args(self): 161 response = TemplateResponse(self.factory.get('/'), '', {}, 162 'application/json', 504) 163 self.assertEqual(response['content-type'], 'application/json') 164 self.assertEqual(response.status_code, 504) -
tests/regressiontests/templates/tests.py
diff -r c67d03486d14 tests/regressiontests/templates/tests.py
a b 27 27 from unicode import unicode_tests 28 28 from nodelist import NodelistTest 29 29 from smartif import * 30 from response import * 30 31 31 32 try: 32 33 from loaders import * -
new file tests/regressiontests/views/templates/debug/render_test.html
diff -r c67d03486d14 tests/regressiontests/views/templates/debug/render_test.html
- + 1 {{ foo }}.{{ bar }}.{{ baz }}.{{ processors }} -
tests/regressiontests/views/tests/__init__.py
diff -r c67d03486d14 tests/regressiontests/views/tests/__init__.py
a b 7 7 from i18n import * 8 8 from specials import * 9 9 from static import * 10 from shortcuts import * -
new file tests/regressiontests/views/tests/shortcuts.py
diff -r c67d03486d14 tests/regressiontests/views/tests/shortcuts.py
- + 1 from django.test import RequestFactory 2 from django.template import Template 3 from django.shortcuts import render 4 5 from regressiontests.templates.response import BaseTemplateResponseTest 6 7 def library_view(request): 8 return render(request, 'debug/render_test.html', 9 {'foo': 'foo', 'baz': 'baz'}) 10 11 def customized_context_view(request): 12 response = library_view(request) 13 response.template_context.update({'bar': 'bar', 'baz': 'spam'}) 14 return response 15 16 def customized_template_view(request): 17 response = library_view(request) 18 response.template_name = Template('context does not matter') 19 return response 20 21 22 class RenderTest(BaseTemplateResponseTest): 23 24 def setUp(self): 25 super(RenderTest, self).setUp() 26 self.request = self.factory.get('/') 27 28 def test_library_view(self): 29 response = library_view(self.request) 30 self.assertEqual(response.content, 'foo..baz.yes\n') 31 32 def test_customized_context(self): 33 response = customized_context_view(self.request) 34 self.assertEqual(response.content, 'foo.bar.spam.yes\n') 35 36 def test_customized_template(self): 37 response = customized_template_view(self.request) 38 self.assertEqual(response.content, 'context does not matter') 39 40 def test_status_and_content_type(self): 41 response = render(self.request, 'base.html', {'foo': 'bar'}, 42 'application/json', 504) 43 self.assertEqual(response.status_code, 504) 44 self.assertEqual(response['content-type'], 'application/json') 45