From f89f1c8acbf5f9d13d52855c49bef53360b1a6e2 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sun, 16 Jan 2011 15:38:03 +0000 Subject: [PATCH] Fixed #15083 -- Corrected the order of TemplateResponse middleware handling, ensuring that custom URLConfs are valid, and that ResponseMiddleware is invoked if the TemplateResponseMiddleware causes errors. Thanks to Sayane for the report. git-svn-id: http://code.djangoproject.com/svn/django/trunk@15226 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/handlers/base.py | 14 ++++----- .../middleware_exceptions/tests.py | 6 ++-- .../templates/alternate_urls.py | 11 +++++++ tests/regressiontests/templates/response.py | 29 ++++++++++++++++++- .../templates/templates/response.html | 1 + tests/regressiontests/templates/views.py | 9 ++++++ 6 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 tests/regressiontests/templates/alternate_urls.py create mode 100644 tests/regressiontests/templates/templates/response.html diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index 9468b1dab9..f216886d56 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -128,6 +128,13 @@ class BaseHandler(object): view_name = callback.__class__.__name__ + '.__call__' # If it's a class raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)) + # If the response supports deferred rendering, apply template + # response middleware and the render the response + if hasattr(response, 'render') and callable(response.render): + for middleware_method in self._template_response_middleware: + response = middleware_method(request, response) + response.render() + except http.Http404, e: logger.warning('Not Found: %s' % request.path, extra={ @@ -166,13 +173,6 @@ class BaseHandler(object): urlresolvers.set_urlconf(None) try: - # If the response supports deferred rendering, apply template - # response middleware and the render the response - if hasattr(response, 'render') and callable(response.render): - for middleware_method in self._template_response_middleware: - response = middleware_method(request, response) - response.render() - # Apply response middleware, regardless of the response for middleware_method in self._response_middleware: response = middleware_method(request, response) diff --git a/tests/regressiontests/middleware_exceptions/tests.py b/tests/regressiontests/middleware_exceptions/tests.py index e68cd52313..e0617076a3 100644 --- a/tests/regressiontests/middleware_exceptions/tests.py +++ b/tests/regressiontests/middleware_exceptions/tests.py @@ -503,9 +503,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest): self.assert_exceptions_handled('/middleware_exceptions/template_response/', ['Test Template Response Exception']) # Check that the right middleware methods have been invoked - self.assert_middleware_usage(pre_middleware, True, True, False, False, False) - self.assert_middleware_usage(bad_middleware, True, True, True, False, False) - self.assert_middleware_usage(post_middleware, True, True, True, False, False) + self.assert_middleware_usage(pre_middleware, True, True, False, True, False) + self.assert_middleware_usage(bad_middleware, True, True, True, True, False) + self.assert_middleware_usage(post_middleware, True, True, True, True, False) def test_process_response_bad_middleware(self): pre_middleware = TestMiddleware() diff --git a/tests/regressiontests/templates/alternate_urls.py b/tests/regressiontests/templates/alternate_urls.py new file mode 100644 index 0000000000..31590a5dbc --- /dev/null +++ b/tests/regressiontests/templates/alternate_urls.py @@ -0,0 +1,11 @@ +# 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), + + # 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 2f0d2c7822..f658b35ac3 100644 --- a/tests/regressiontests/templates/response.py +++ b/tests/regressiontests/templates/response.py @@ -1,6 +1,6 @@ import os from django.utils import unittest -from django.test import RequestFactory +from django.test import RequestFactory, TestCase from django.conf import settings import django.template.context from django.template import Template, Context, RequestContext @@ -11,6 +11,13 @@ def test_processor(request): return {'processors': 'yes'} test_processor_name = 'regressiontests.templates.response.test_processor' + +# A test middleware that installs a temporary URLConf +class CustomURLConfMiddleware(object): + def process_request(self, request): + request.urlconf = 'regressiontests.templates.alternate_urls' + + class BaseTemplateResponseTest(unittest.TestCase): # tests rely on fact that global context # processors should only work when RequestContext is used. @@ -179,3 +186,23 @@ class TemplateResponseTest(BaseTemplateResponseTest): rc = response.resolve_context(response.context_data) self.assertEqual(rc.current_app, 'foobar') + + +class CustomURLConfTest(TestCase): + urls = 'regressiontests.templates.urls' + + def setUp(self): + self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES + settings.MIDDLEWARE_CLASSES = list(settings.MIDDLEWARE_CLASSES) + [ + 'regressiontests.templates.response.CustomURLConfMiddleware' + ] + + def tearDown(self): + settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES + + 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/') + + diff --git a/tests/regressiontests/templates/templates/response.html b/tests/regressiontests/templates/templates/response.html new file mode 100644 index 0000000000..7c442fb453 --- /dev/null +++ b/tests/regressiontests/templates/templates/response.html @@ -0,0 +1 @@ +{% load url from future %}This is where you can find the snark: {% url "snark" %} \ No newline at end of file diff --git a/tests/regressiontests/templates/views.py b/tests/regressiontests/templates/views.py index ca3cecde8f..ed15893239 100644 --- a/tests/regressiontests/templates/views.py +++ b/tests/regressiontests/templates/views.py @@ -1,4 +1,7 @@ # Fake views for testing url reverse lookup +from django.http import HttpResponse +from django.template.response import TemplateResponse + def index(request): pass @@ -11,3 +14,9 @@ def client_action(request, id, action): def client2(request, tag): pass + +def template_response_view(request): + return TemplateResponse(request, 'response.html', {}) + +def snark(request): + return HttpResponse('Found him!')