Ticket #12816: render_shortcut.3.diff
File render_shortcut.3.diff, 14.7 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 from django.utils import unittest 2 from django.test import RequestFactory 3 from django.conf import settings 4 from django.template import Template, Context, RequestContext 5 from django.template.response import TemplateResponse, SimpleTemplateResponse 6 import django.template.context 7 8 def test_processor(request): 9 return {'processors': 'yes'} 10 test_processor_name = 'regressiontests.templates.response.test_processor' 11 12 class BaseTemplateResponseTest(unittest.TestCase): 13 # tests rely on fact that global context 14 # processors should only work when RequestContext is used. 15 16 def setUp(self): 17 cp = list(settings.TEMPLATE_CONTEXT_PROCESSORS) 18 self._old_processors = cp[:] 19 settings.TEMPLATE_CONTEXT_PROCESSORS = cp + [test_processor_name] 20 21 def tearDown(self): 22 settings.TEMPLATE_CONTEXT_PROCESSORS = tuple(self._old_processors) 23 # Force re-evaluation of the contex processor list 24 django.template.context._standard_context_processors = None 25 26 27 class SimpleTemplateResponseTest(BaseTemplateResponseTest): 28 29 def _response(self, template='foo', *args, **kwargs): 30 return SimpleTemplateResponse(Template(template), *args, **kwargs) 31 32 def test_template_resolving(self): 33 34 # templates from 'templates/templates/..' dir can't be loaded so 35 # the base.html template is reused. It is assumed that base.html 36 # contains 'Django Internal Tests' string. 37 38 response = SimpleTemplateResponse('base.html') 39 self.assertIn('Django Internal Tests', response.content) 40 41 response = SimpleTemplateResponse(['foo.html', 'base.html']) 42 self.assertIn('Django Internal Tests', response.content) 43 44 response = self._response() 45 self.assertEqual(response.content, 'foo') 46 47 def test_explicit_baking(self): 48 # explicit baking 49 response = self._response() 50 self.assertFalse(response.baked) 51 response.bake() 52 self.assertTrue(response.baked) 53 54 def test_force_bake(self): 55 # response is not re-baked without the force_bake call 56 response = self._response() 57 self.assertFalse(response.baked) 58 self.assertEqual(response.content, 'foo') 59 60 response.template_name = Template('bar{{ baz }}') 61 self.assertEqual(response.content, 'foo') 62 response.bake() 63 self.assertEqual(response.content, 'foo') 64 response.force_bake() 65 self.assertEqual(response.content, 'bar') 66 67 response.template_context = {'baz': 'baz'} 68 self.assertEqual(response.content, 'bar') 69 response.bake() 70 self.assertEqual(response.content, 'bar') 71 response.force_bake() 72 self.assertEqual(response.content, 'barbaz') 73 74 response.template_context = {'baz': 'spam'} 75 for x in response: 76 pass 77 self.assertEqual(response.content, 'barbaz') 78 79 def test_baking_on_iteration(self): 80 # response becomes baked after first iteration 81 response = self._response() 82 self.assertFalse(response.baked) 83 for x in response: 84 pass 85 self.assertTrue(response.baked) 86 87 def test_baking_on_access(self): 88 # the response is baked when content is accessed 89 response = self._response() 90 self.assertFalse(response.baked) 91 content = response.content 92 self.assertTrue(response.baked) 93 self.assertEqual(content, 'foo') 94 95 def test_set_content(self): 96 # content can be overriden 97 response = self._response() 98 self.assertFalse(response.baked) 99 response.content = 'spam' 100 self.assertTrue(response.baked) 101 self.assertEqual(response.content, 'spam') 102 response.content = 'baz' 103 self.assertEqual(response.content, 'baz') 104 105 def test_dict_context(self): 106 response = self._response('{{ foo }}{{ processors }}', 107 {'foo': 'bar'}) 108 self.assertEqual(response.template_context, {'foo': 'bar'}) 109 self.assertEqual(response.content, 'bar') 110 111 def test_context_instance(self): 112 response = self._response('{{ foo }}{{ processors }}', 113 Context({'foo': 'bar'})) 114 self.assertEqual(response.template_context.__class__, Context) 115 self.assertEqual(response.content, 'bar') 116 117 def test_kwargs(self): 118 response = self._response(content_type = 'application/json', status=504) 119 self.assertEqual(response['content-type'], 'application/json') 120 self.assertEqual(response.status_code, 504) 121 122 def test_args(self): 123 response = SimpleTemplateResponse('', {}, 'application/json', 504) 124 self.assertEqual(response['content-type'], 'application/json') 125 self.assertEqual(response.status_code, 504) 126 127 128 class TemplateResponseTest(BaseTemplateResponseTest): 129 def setUp(self): 130 self.factory = RequestFactory() 131 super(TemplateResponseTest, self).setUp() 132 133 def _response(self, template='foo', *args, **kwargs): 134 return TemplateResponse(self.factory.get('/'), Template(template), 135 *args, **kwargs) 136 137 def test_render(self): 138 response = self._response('{{ foo }}{{ processors }}') 139 self.assertEqual(response.content, 'yes') 140 141 def test_render_with_requestcontext(self): 142 response = self._response('{{ foo }}{{ processors }}', 143 {'foo': 'bar'}) 144 self.assertEqual(response.content, 'baryes') 145 146 def test_render_with_context(self): 147 response = self._response('{{ foo }}{{ processors }}', 148 Context({'foo': 'bar'})) 149 self.assertEqual(response.content, 'bar') 150 151 def test_kwargs(self): 152 response = self._response(content_type = 'application/json', status=504) 153 self.assertEqual(response['content-type'], 'application/json') 154 self.assertEqual(response.status_code, 504) 155 156 def test_args(self): 157 response = TemplateResponse(self.factory.get('/'), '', {}, 158 'application/json', 504) 159 self.assertEqual(response['content-type'], 'application/json') 160 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 }}.{{ user.is_anonymous }} -
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.utils import unittest 2 from django.test import RequestFactory 3 from django.template import Template 4 from django.shortcuts import render 5 6 def library_view(request): 7 return render(request, 'debug/render_test.html', 8 {'foo': 'foo', 'baz': 'baz'}) 9 10 def customized_context_view(request): 11 response = library_view(request) 12 response.template_context.update({'bar': 'bar', 'baz': 'spam'}) 13 return response 14 15 def customized_template_view(request): 16 response = library_view(request) 17 response.template_name = Template('context does not matter') 18 return response 19 20 21 class RenderTest(unittest.TestCase): 22 23 def setUp(self): 24 self.factory = RequestFactory() 25 self.request = self.factory.get('/') 26 27 def test_library_view(self): 28 response = library_view(self.request) 29 self.assertEqual(response.content, 'foo..baz.True\n') 30 31 def test_customized_context(self): 32 response = customized_context_view(self.request) 33 self.assertEqual(response.content, 'foo.bar.spam.True\n') 34 35 def test_customized_template(self): 36 response = customized_template_view(self.request) 37 self.assertEqual(response.content, 'context does not matter') 38 39 def test_status_and_content_type(self): 40 response = render(self.request, 'base.html', {'foo': 'bar'}, 41 'application/json', 504) 42 self.assertEqual(response.status_code, 504) 43 self.assertEqual(response['content-type'], 'application/json') 44