Ticket #12816: render_shortcut.4.diff
File render_shortcut.4.diff, 14.8 KB (added by , 14 years ago) |
---|
-
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 -
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