From 18bb674234e836ba3a8aa6b63c9001100a03b7d0 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 3 Jan 2011 11:57:26 -0500 Subject: [PATCH 1/5] TemplateResponse: accept a current_app parameter for RequestContext This simplifies cases such as the Django admin conversion in #15008 where the need to set current_app requires an extra import and creating the RequestContext manually. --- django/template/response.py | 7 +++++-- tests/regressiontests/templates/response.py | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/django/template/response.py b/django/template/response.py index d89fee0..629461a 100644 --- a/django/template/response.py +++ b/django/template/response.py @@ -90,11 +90,14 @@ class SimpleTemplateResponse(HttpResponse): class TemplateResponse(SimpleTemplateResponse): def __init__(self, request, template, context=None, mimetype=None, - status=None, content_type=None): + status=None, content_type=None, current_app=None): # self.request gets over-written by django.test.client.Client - and # unlike context_data and template_name the _request should not # be considered part of the public API. self._request = request + # As a convenience we'll allow callers to provide current_app without + # having to avoid needing to create the RequestContext directly + self._current_app = current_app super(TemplateResponse, self).__init__( template, context, mimetype, status, content_type) @@ -105,4 +108,4 @@ class TemplateResponse(SimpleTemplateResponse): if isinstance(context, Context): return context else: - return RequestContext(self._request, context) + return RequestContext(self._request, context, current_app=self._current_app) diff --git a/tests/regressiontests/templates/response.py b/tests/regressiontests/templates/response.py index 8bdf7f4..2f0d2c7 100644 --- a/tests/regressiontests/templates/response.py +++ b/tests/regressiontests/templates/response.py @@ -172,3 +172,10 @@ class TemplateResponseTest(BaseTemplateResponseTest): 'application/json', 504) self.assertEqual(response['content-type'], 'application/json') self.assertEqual(response.status_code, 504) + + def test_custom_app(self): + response = self._response('{{ foo }}', current_app="foobar") + + rc = response.resolve_context(response.context_data) + + self.assertEqual(rc.current_app, 'foobar') -- 1.7.0.2 From fc912c9def744d5a504db15a8061610eee899597 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 3 Jan 2011 21:33:30 -0500 Subject: [PATCH 2/5] Add current_app support to shortcuts.render This parallels the earlier change to TemplateResponse, providing a convenient way to pass current_app without having to instantiate a RequestContext by hand. See http://code.djangoproject.com/ticket/15010 --- django/shortcuts/__init__.py | 10 +++++++++- tests/regressiontests/views/tests/shortcuts.py | 4 ++++ tests/regressiontests/views/urls.py | 2 +- tests/regressiontests/views/views.py | 6 ++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/django/shortcuts/__init__.py b/django/shortcuts/__init__.py index b7d69b5..6347d3f 100644 --- a/django/shortcuts/__init__.py +++ b/django/shortcuts/__init__.py @@ -29,7 +29,15 @@ def render(request, *args, **kwargs): 'content_type': kwargs.pop('content_type', None), 'status': kwargs.pop('status', None), } - kwargs['context_instance'] = kwargs.get('context_instance', RequestContext(request)) + + if 'context_instance' in kwargs: + context_instance = kwargs.pop("context_instance") + else: + current_app = kwargs.pop("current_app", None) + context_instance = RequestContext(request, current_app=current_app) + + kwargs['context_instance'] = context_instance + return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs) diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py index 3f260fe..fa8408c 100644 --- a/tests/regressiontests/views/tests/shortcuts.py +++ b/tests/regressiontests/views/tests/shortcuts.py @@ -56,3 +56,7 @@ class ShortcutTests(TestCase): self.assertEquals(response.status_code, 403) self.assertEquals(response.content, 'FOO.BAR../path/to/static/media\n') + def test_render_with_current_app(self): + response = self.client.get('/views/shortcuts/render/current_app/') + self.assertEquals(response.context.current_app, "foobar_app") + diff --git a/tests/regressiontests/views/urls.py b/tests/regressiontests/views/urls.py index 7cba5f6..7dad098 100644 --- a/tests/regressiontests/views/urls.py +++ b/tests/regressiontests/views/urls.py @@ -151,7 +151,7 @@ urlpatterns += patterns('regressiontests.views.views', (r'^shortcuts/render/base_context/$', 'render_view_with_base_context'), (r'^shortcuts/render/content_type/$', 'render_view_with_content_type'), (r'^shortcuts/render/status/$', 'render_view_with_status'), - + (r'^shortcuts/render/current_app/$', 'render_view_with_current_app'), ) # simple generic views. diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index ec017bd..9c9b4c5 100644 --- a/tests/regressiontests/views/views.py +++ b/tests/regressiontests/views/views.py @@ -101,3 +101,9 @@ def render_view_with_status(request): 'foo': 'FOO', 'bar': 'BAR', }, status=403) + +def render_view_with_current_app(request): + return render(request, 'debug/render_test.html', { + 'foo': 'FOO', + 'bar': 'BAR', + }, current_app="foobar_app") -- 1.7.0.2 From d1024ace8965230d5eac7d2a7a8cefeeefc3b36d Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 3 Jan 2011 21:46:51 -0500 Subject: [PATCH 3/5] Documentation for current_app on render shortcut and TemplateResponse Basic documentation and a pointer to the namespaced URL resolution strategy. --- docs/ref/template-response.txt | 7 ++++++- docs/topics/http/shortcuts.txt | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt index 3b136b6..d4fe2c4 100644 --- a/docs/ref/template-response.txt +++ b/docs/ref/template-response.txt @@ -129,7 +129,7 @@ TemplateResponse objects Methods ------- -.. method:: TemplateResponse.__init__(request, template, context=None, mimetype=None, status=None, content_type=None) +.. method:: TemplateResponse.__init__(request, template, context=None, mimetype=None, status=None, content_type=None, current_app=None) Instantiates an ``TemplateResponse`` object with the given template, context, MIME type and HTTP status. @@ -158,6 +158,11 @@ Methods ``content_type`` is used. If neither is given, :setting:`DEFAULT_CONTENT_TYPE` is used. + ``current_app`` + A hint indicating which application contains the current view. See the + :ref:`namespaced URL resolution strategy ` + for more information. + The rendering process ===================== diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt index 1c1dc9e..9d72521 100644 --- a/docs/topics/http/shortcuts.txt +++ b/docs/topics/http/shortcuts.txt @@ -15,7 +15,7 @@ introduce controlled coupling for convenience's sake. ``render`` ========== -.. function:: render(request, template[, dictionary][, context_instance][, content_type][, status]) +.. function:: render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app]) .. versionadded:: 1.3 @@ -23,7 +23,7 @@ introduce controlled coupling for convenience's sake. :class:`~django.http.HttpResponse` object with that rendered text. :func:`render()` is the same as a call to - :func:`render_to_response()` with a context_instance argument that + :func:`render_to_response()` with a `context_instance` argument that that forces the use of a :class:`RequestContext`. Required arguments @@ -55,6 +55,11 @@ Optional arguments ``status`` The status code for the response. Defaults to ``200``. +``current_app`` + A hint indicating which application contains the current view. See the + :ref:`namespaced URL resolution strategy ` + for more information. + Example ------- -- 1.7.0.2 From 3525c20f5c7375c3ab13b5a509b0be6c588a0254 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 3 Jan 2011 22:05:13 -0500 Subject: [PATCH 4/5] render(): Added a simple current_app sanity check This enforces a simple policy: render() will only set current_app on RequestContexts which it creates. --- django/shortcuts/__init__.py | 2 ++ tests/regressiontests/views/tests/shortcuts.py | 3 +++ tests/regressiontests/views/urls.py | 1 + tests/regressiontests/views/views.py | 8 ++++++++ 4 files changed, 14 insertions(+), 0 deletions(-) diff --git a/django/shortcuts/__init__.py b/django/shortcuts/__init__.py index 6347d3f..98116f0 100644 --- a/django/shortcuts/__init__.py +++ b/django/shortcuts/__init__.py @@ -32,6 +32,8 @@ def render(request, *args, **kwargs): if 'context_instance' in kwargs: context_instance = kwargs.pop("context_instance") + if kwargs.get("current_app", None): + raise ValueError("If you provide a context_instance you must set its current_app before calling render()") else: current_app = kwargs.pop("current_app", None) context_instance = RequestContext(request, current_app=current_app) diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py index fa8408c..c974348 100644 --- a/tests/regressiontests/views/tests/shortcuts.py +++ b/tests/regressiontests/views/tests/shortcuts.py @@ -60,3 +60,6 @@ class ShortcutTests(TestCase): response = self.client.get('/views/shortcuts/render/current_app/') self.assertEquals(response.context.current_app, "foobar_app") + def test_render_with_current_app_conflict(self): + self.assertRaises(ValueError, self.client.get, '/views/shortcuts/render/current_app_conflict/') + diff --git a/tests/regressiontests/views/urls.py b/tests/regressiontests/views/urls.py index 7dad098..a170efb 100644 --- a/tests/regressiontests/views/urls.py +++ b/tests/regressiontests/views/urls.py @@ -152,6 +152,7 @@ urlpatterns += patterns('regressiontests.views.views', (r'^shortcuts/render/content_type/$', 'render_view_with_content_type'), (r'^shortcuts/render/status/$', 'render_view_with_status'), (r'^shortcuts/render/current_app/$', 'render_view_with_current_app'), + (r'^shortcuts/render/current_app_conflict/$', 'render_view_with_current_app_conflict'), ) # simple generic views. diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index 9c9b4c5..e4e7c3d 100644 --- a/tests/regressiontests/views/views.py +++ b/tests/regressiontests/views/views.py @@ -107,3 +107,11 @@ def render_view_with_current_app(request): 'foo': 'FOO', 'bar': 'BAR', }, current_app="foobar_app") + +def render_view_with_current_app_conflict(request): + # This should fail because we don't passing both a current_app and + # context_instance: + return render(request, 'debug/render_test.html', { + 'foo': 'FOO', + 'bar': 'BAR', + }, current_app="foobar_app", context_instance=RequestContext(request)) -- 1.7.0.2 From 67b08c22bffeb7ab4014fa22b99a67f3c684240e Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 3 Jan 2011 22:13:48 -0500 Subject: [PATCH 5/5] shortcuts.render(): test update * Add positive assertion that current_app is not accidentally set --- tests/regressiontests/views/tests/shortcuts.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py index c974348..c5f664e 100644 --- a/tests/regressiontests/views/tests/shortcuts.py +++ b/tests/regressiontests/views/tests/shortcuts.py @@ -38,6 +38,7 @@ class ShortcutTests(TestCase): self.assertEquals(response.status_code, 200) self.assertEquals(response.content, 'FOO.BAR../path/to/static/media\n') self.assertEquals(response['Content-Type'], 'text/html; charset=utf-8') + self.assertEquals(response.context.current_app, None) def test_render_with_base_context(self): response = self.client.get('/views/shortcuts/render/base_context/') -- 1.7.0.2