From f89f1c8acbf5f9d13d52855c49bef53360b1a6e2 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee <russell@keith-magee.com>
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!')