[1.10.x] Fixed #26915 -- Fixed regression handling responses returned from view middleware.

Backport of 44a6b40280 from master
This commit is contained in:
Alex Hill 2016-07-19 16:45:32 +08:00 committed by Tim Graham
parent 13c107b149
commit d53e3c1e07
5 changed files with 85 additions and 10 deletions

View File

@ -177,13 +177,14 @@ class BaseHandler(object):
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
return response
break
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
response = self.process_exception_by_middleware(e, request)
if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
response = self.process_exception_by_middleware(e, request)
# Complain if the view returned None (a common error).
if response is None:

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
from django.http import Http404, HttpResponse
from django.template import engines
from django.template.response import TemplateResponse
log = []
@ -40,9 +41,15 @@ class ProcessViewNoneMiddleware(BaseMiddleware):
return None
class ProcessViewTemplateResponseMiddleware(BaseMiddleware):
def process_view(self, request, view_func, view_args, view_kwargs):
template = engines['django'].from_string('Processed view {{ view }}{% for m in mw %}\n{{ m }}{% endfor %}')
return TemplateResponse(request, template, {'mw': [self.__class__.__name__], 'view': view_func.__name__})
class TemplateResponseMiddleware(BaseMiddleware):
def process_template_response(self, request, response):
response.template_name = engines['django'].from_string('template-response middleware')
response.context_data['mw'].append(self.__class__.__name__)
return response

View File

@ -56,12 +56,25 @@ class ViewMiddleware(TestMiddleware):
return HttpResponse('View Middleware')
class TemplateResponseViewMiddleware(TestMiddleware):
def process_view(self, request, view_func, view_args, view_kwargs):
super(TemplateResponseViewMiddleware, self).process_view(request, view_func, view_args, view_kwargs)
template = engines['django'].from_string('TemplateResponse View Middleware')
return TemplateResponse(request, template)
class ResponseMiddleware(TestMiddleware):
def process_response(self, request, response):
super(ResponseMiddleware, self).process_response(request, response)
return HttpResponse('Response Middleware')
class ContentAccessingResponseMiddleware(TestMiddleware):
def process_response(self, request, response):
super(ContentAccessingResponseMiddleware, self).process_response(request, response)
return HttpResponse('Content-accessing Response Middleware: %d' % len(response.content))
class TemplateResponseMiddleware(TestMiddleware):
def process_template_response(self, request, response):
super(TemplateResponseMiddleware, self).process_template_response(request, response)
@ -512,6 +525,30 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(middleware, True, True, True, True, False)
def test_templateresponse_from_process_view_rendered(self):
view_middleware = TemplateResponseViewMiddleware()
# ContentAccessingResponseMiddleware tries to access response.content
# in its process_response().
post_middleware = ContentAccessingResponseMiddleware()
self._add_middleware(view_middleware)
self._add_middleware(post_middleware)
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
self.assert_middleware_usage(view_middleware, True, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, True, False)
def test_templateresponse_from_process_view_passed_to_template_response_middleware(self):
"""
TemplateResponses returned from process_view() should be passed to any
process_template_response().
"""
view_middleware = TemplateResponseViewMiddleware()
resp_middleware = TemplateResponseMiddleware()
self._add_middleware(view_middleware)
self._add_middleware(resp_middleware)
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
self.assert_middleware_usage(view_middleware, True, True, True, True, False)
self.assert_middleware_usage(resp_middleware, True, True, True, True, False)
class BadMiddlewareTests(BaseMiddlewareExceptionTest):

View File

@ -22,10 +22,40 @@ class MiddlewareTests(SimpleTestCase):
response = self.client.get('/middleware_exceptions/view/')
self.assertEqual(response.content, b'Processed view normal_view')
@override_settings(MIDDLEWARE=[
'middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware',
'middleware_exceptions.middleware.LogMiddleware',
])
def test_templateresponse_from_process_view_rendered(self):
"""
TemplateResponses returned from process_view() must be rendered before
being passed to any middleware that tries to access response.content,
such as middleware_exceptions.middleware.LogMiddleware.
"""
response = self.client.get('/middleware_exceptions/view/')
self.assertEqual(response.content, b'Processed view normal_view\nProcessViewTemplateResponseMiddleware')
@override_settings(MIDDLEWARE=[
'middleware_exceptions.middleware.ProcessViewTemplateResponseMiddleware',
'middleware_exceptions.middleware.TemplateResponseMiddleware',
])
def test_templateresponse_from_process_view_passed_to_process_template_response(self):
"""
TemplateResponses returned from process_view() should be passed to any
template response middleware.
"""
response = self.client.get('/middleware_exceptions/view/')
expected_lines = [
b'Processed view normal_view',
b'ProcessViewTemplateResponseMiddleware',
b'TemplateResponseMiddleware',
]
self.assertEqual(response.content, b'\n'.join(expected_lines))
@override_settings(MIDDLEWARE=['middleware_exceptions.middleware.TemplateResponseMiddleware'])
def test_process_template_response(self):
response = self.client.get('/middleware_exceptions/template_response/')
self.assertEqual(response.content, b'template-response middleware')
self.assertEqual(response.content, b'template_response OK\nTemplateResponseMiddleware')
@override_settings(MIDDLEWARE=['middleware_exceptions.middleware.LogMiddleware'])
def test_view_exception_converted_before_middleware(self):

View File

@ -9,8 +9,8 @@ def normal_view(request):
def template_response(request):
template = engines['django'].from_string('OK')
return TemplateResponse(request, template)
template = engines['django'].from_string('template_response OK{% for m in mw %}\n{{ m }}{% endfor %}')
return TemplateResponse(request, template, context={'mw': []})
def template_response_error(request):