Fixed #12815 -- Added TemplateResponse, a lazy-evaluated Response class. Thanks to Simon Willison for the original idea, and to Mikhail Korobov and Ivan Sagalaev for their assistance, including the draft patch from Mikhail.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14850 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2010-12-07 13:57:01 +00:00
parent 22fc30be5a
commit e0dcd7666a
19 changed files with 842 additions and 210 deletions

View File

@ -273,6 +273,7 @@ answer newbie questions, and generally made Django that much better:
Igor Kolar <ike@email.si>
Tomáš Kopeček <permonik@m6.cz>
Gasper Koren
Mikhail Korobov <kmike84@googlemail.com>
Martin Kosír <martin@martinkosir.net>
Arthur Koziel <http://arthurkoziel.com>
Meir Kriheli <http://mksoft.co.il/>

View File

@ -103,7 +103,7 @@ class BaseTest(TestCase):
storage = self.get_storage()
self.assertFalse(storage.added_new)
storage.add(constants.INFO, 'Test message 1')
self.assert_(storage.added_new)
self.assertTrue(storage.added_new)
storage.add(constants.INFO, 'Test message 2', extra_tags='tag')
self.assertEqual(len(storage), 2)
@ -180,6 +180,26 @@ class BaseTest(TestCase):
for msg in data['messages']:
self.assertContains(response, msg)
def test_with_template_response(self):
settings.MESSAGE_LEVEL = constants.DEBUG
data = {
'messages': ['Test message %d' % x for x in xrange(10)],
}
show_url = reverse('django.contrib.messages.tests.urls.show_template_response')
for level in self.levels.keys():
add_url = reverse('django.contrib.messages.tests.urls.add_template_response',
args=(level,))
response = self.client.post(add_url, data, follow=True)
self.assertRedirects(response, show_url)
self.assertTrue('messages' in response.context)
for msg in data['messages']:
self.assertContains(response, msg)
# there shouldn't be any messages on second GET request
response = self.client.get(show_url)
for msg in data['messages']:
self.assertNotContains(response, msg)
def test_multiple_posts(self):
"""
Tests that messages persist properly when multiple POSTs are made

View File

@ -2,9 +2,20 @@ from django.conf.urls.defaults import *
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render_to_response
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext, Template
from django.template.response import TemplateResponse
TEMPLATE = """{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
{{ message }}
</li>
{% endfor %}
</ul>
{% endif %}
"""
def add(request, message_type):
# don't default to False here, because we want to test that it defaults
@ -16,24 +27,27 @@ def add(request, message_type):
fail_silently=fail_silently)
else:
getattr(messages, message_type)(request, msg)
show_url = reverse('django.contrib.messages.tests.urls.show')
return HttpResponseRedirect(show_url)
def add_template_response(request, message_type):
for msg in request.POST.getlist('messages'):
getattr(messages, message_type)(request, msg)
show_url = reverse('django.contrib.messages.tests.urls.show_template_response')
return HttpResponseRedirect(show_url)
def show(request):
t = Template("""{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
{{ message }}
</li>
{% endfor %}
</ul>
{% endif %}""")
t = Template(TEMPLATE)
return HttpResponse(t.render(RequestContext(request)))
def show_template_response(request):
return TemplateResponse(request, Template(TEMPLATE))
urlpatterns = patterns('',
('^add/(debug|info|success|warning|error)/$', add),
('^show/$', show),
('^template_response/add/(debug|info|success|warning|error)/$', add_template_response),
('^template_response/show/$', show_template_response),
)

View File

@ -21,6 +21,7 @@ class BaseHandler(object):
def __init__(self):
self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE_CLASSES.
@ -30,16 +31,16 @@ class BaseHandler(object):
from django.conf import settings
from django.core import exceptions
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
request_middleware = []
for middleware_path in settings.MIDDLEWARE_CLASSES:
try:
dot = middleware_path.rindex('.')
mw_module, mw_classname = middleware_path.rsplit('.', 1)
except ValueError:
raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path)
mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
try:
mod = import_module(mw_module)
except ImportError, e:
@ -48,7 +49,6 @@ class BaseHandler(object):
mw_class = getattr(mod, mw_classname)
except AttributeError:
raise exceptions.ImproperlyConfigured('Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname))
try:
mw_instance = mw_class()
except exceptions.MiddlewareNotUsed:
@ -58,6 +58,8 @@ class BaseHandler(object):
request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, 'process_view'):
self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, 'process_response'):
self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, 'process_exception'):
@ -164,6 +166,13 @@ 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)

108
django/template/response.py Normal file
View File

@ -0,0 +1,108 @@
from django.http import HttpResponse
from django.template import loader, Context, RequestContext
class ContentNotRenderedError(Exception):
pass
class SimpleTemplateResponse(HttpResponse):
def __init__(self, template, context=None, mimetype=None, status=None,
content_type=None):
# It would seem obvious to call these next two members 'template' and
# 'context', but those names are reserved as part of the test Client API.
# To avoid the name collision, we use
# tricky-to-debug problems
self.template_name = template
self.context_data = context
# _is_rendered tracks whether the template and context has been baked into
# a final response.
self._is_rendered = False
# content argument doesn't make sense here because it will be replaced
# with rendered template so we always pass empty string in order to
# prevent errors and provide shorter signature.
super(SimpleTemplateResponse, self).__init__('', mimetype, status,
content_type)
def resolve_template(self, template):
"Accepts a template object, path-to-template or list of paths"
if isinstance(template, (list, tuple)):
return loader.select_template(template)
elif isinstance(template, basestring):
return loader.get_template(template)
else:
return template
def resolve_context(self, context):
"""Convert context data into a full Context object
(assuming it isn't already a Context object).
"""
if isinstance(context, Context):
return context
else:
return Context(context)
@property
def rendered_content(self):
"""Returns the freshly rendered content for the template and context
described by the TemplateResponse.
This *does not* set the final content of the response. To set the
response content, you must either call render(), or set the
content explicitly using the value of this property.
"""
template = self.resolve_template(self.template_name)
context = self.resolve_context(self.context_data)
content = template.render(context)
return content
def render(self):
"""Render (thereby finalizing) the content of the response.
If the content has already been rendered, this is a no-op.
Returns the baked response instance.
"""
if not self._is_rendered:
self._set_content(self.rendered_content)
return self
is_rendered = property(lambda self: self._is_rendered)
def __iter__(self):
if not self._is_rendered:
raise ContentNotRenderedError('The response content must be rendered before it can be iterated over.')
return super(SimpleTemplateResponse, self).__iter__()
def _get_content(self):
if not self._is_rendered:
raise ContentNotRenderedError('The response content must be rendered before it can be accessed.')
return super(SimpleTemplateResponse, self)._get_content()
def _set_content(self, value):
"Overrides rendered content, unless you later call render()"
super(SimpleTemplateResponse, self)._set_content(value)
self._is_rendered = True
content = property(_get_content, _set_content)
class TemplateResponse(SimpleTemplateResponse):
def __init__(self, request, template, context=None, mimetype=None,
status=None, content_type=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
super(TemplateResponse, self).__init__(
template, context, mimetype, status, content_type)
def resolve_context(self, context):
"""Convert context data into a full RequestContext object
(assuming it isn't already a Context object).
"""
if isinstance(context, Context):
return context
else:
return RequestContext(self._request, context)

View File

@ -1,6 +1,7 @@
from django import http
from django.core.exceptions import ImproperlyConfigured
from django.template import RequestContext, loader
from django.template.response import TemplateResponse
from django.utils.functional import update_wrapper
from django.utils.log import getLogger
from django.utils.decorators import classonlymethod
@ -81,59 +82,29 @@ class TemplateResponseMixin(object):
A mixin that can be used to render a template.
"""
template_name = None
response_class = TemplateResponse
def render_to_response(self, context):
def render_to_response(self, context, **response_kwargs):
"""
Returns a response with a template rendered with the given context.
"""
return self.get_response(self.render_template(context))
def get_response(self, content, **httpresponse_kwargs):
"""
Construct an `HttpResponse` object.
"""
return http.HttpResponse(content, **httpresponse_kwargs)
def render_template(self, context):
"""
Render the template with a given context.
"""
context_instance = self.get_context_instance(context)
return self.get_template().render(context_instance)
def get_context_instance(self, context):
"""
Get the template context instance. Must return a Context (or subclass)
instance.
"""
return RequestContext(self.request, context)
def get_template(self):
"""
Get a ``Template`` object for the given request.
"""
names = self.get_template_names()
if not names:
raise ImproperlyConfigured(u"'%s' must provide template_name."
% self.__class__.__name__)
return self.load_template(names)
return self.response_class(
request = self.request,
template = self.get_template_names(),
context = context,
**response_kwargs
)
def get_template_names(self):
"""
Return a list of template names to be used for the request. Must return
a list. May not be called if get_template is overridden.
Returns a list of template names to be used for the request. Must return
a list. May not be called if render_to_response is overridden.
"""
if self.template_name is None:
return []
else:
return [self.template_name]
def load_template(self, names):
"""
Load a list of templates using the default template loader.
"""
return loader.select_template(names)
class TemplateView(TemplateResponseMixin, View):
"""

View File

@ -93,7 +93,9 @@ The view layer
:doc:`View functions <topics/http/views>` |
:doc:`Shortcuts <topics/http/shortcuts>`
* **Reference:** :doc:`Request/response objects <ref/request-response>`
* **Reference:**
:doc:`Request/response objects <ref/request-response>` |
:doc:`TemplateResponse objects <ref/template-response>`
* **File uploads:**
:doc:`Overview <topics/http/file-uploads>` |

View File

@ -76,39 +76,25 @@ TemplateResponseMixin
The path to the template to use when rendering the view.
.. method:: render_to_response(context)
.. attribute:: response_class
Returns a full composed HttpResponse instance, ready to be returned to
the user.
The response class to be returned by ``render_to_response`` method.
Default is
:class:`TemplateResponse <django.template.response.TemplateResponse>`.
The template and context of TemplateResponse instances can be
altered later (e.g. in
:ref:`template response middleware <template-response-middleware>`).
Calls :meth:`~TemplateResponseMixin.render_template()` to build the
content of the response, and
:meth:`~TemplateResponseMixin.get_response()` to construct the
:class:`~django.http.HttpResponse` object.
Create TemplateResponse subclass and pass set it to
``template_response_class`` if you need custom template loading or
custom context object instantiation.
.. method:: get_response(content, **httpresponse_kwargs)
.. method:: render_to_response(context, **response_kwargs)
Constructs the :class:`~django.http.HttpResponse` object around the
given content. If any keyword arguments are provided, they will be
passed to the constructor of the :class:`~django.http.HttpResponse`
instance.
Returns a ``self.template_response_class`` instance.
.. method:: render_template(context)
Calls :meth:`~TemplateResponseMixin.get_context_instance()` to obtain
the :class:`Context` instance to use for rendering, and calls
:meth:`TemplateReponseMixin.get_template()` to load the template that
will be used to render the final content.
.. method:: get_context_instance(context)
Turns the data dictionary ``context`` into an actual context instance
that can be used for rendering.
By default, constructs a :class:`~django.template.RequestContext`
instance.
.. method:: get_template()
If any keyword arguments are provided, they will be
passed to the constructor of the response instance.
Calls :meth:`~TemplateResponseMixin.get_template_names()` to obtain the
list of template names that will be searched looking for an existent
@ -123,10 +109,6 @@ TemplateResponseMixin
default implementation will return a list containing
:attr:`TemplateResponseMixin.template_name` (if it is specified).
.. method:: load_template(names)
Loads and returns a template found by searching the list of ``names``
for a match. Uses Django's default template loader.
Single object mixins
--------------------

View File

@ -16,6 +16,7 @@ API Reference
middleware
models/index
request-response
template-response
settings
signals
templates/index

View File

@ -0,0 +1,211 @@
===========================================
TemplateResponse and SimpleTemplateResponse
===========================================
.. versionadded:: 1.3
.. module:: django.template.response
:synopsis: Classes dealing with lazy-rendered HTTP responses.
Standard HttpResponse objects are static structures. They are provided
with a block of pre-rendered content at time of construction, and
while that content can be modified, it isn't in a form that makes it
easy to perform modifications.
However, it can sometimes be beneficial to allow decorators or
middleware to modify a response *after* it has been constructed by the
view. For example, you may want to change the template that is used,
or put additional data into the context.
TemplateResponse provides a way to do just that. Unlike basic
HttpResponse objects, TemplateResponse objects retain the details of
the template and context that was provided by the view to compute the
response. The final output of the response is not computed until
it is needed, later in the response process.
TemplateResponse objects
========================
.. class:: SimpleTemplateResponse()
Attributes
----------
.. attribute:: SimpleTemplateResponse.template_name
The name of the template to be rendered. Accepts
:class:`django.template.Template` object, path to template or list
of paths.
Example: ``['foo.html', 'path/to/bar.html']``
.. attribute:: SimpleTemplateResponse.context_data
The context data to be used when rendering the template. It can be
a dictionary or a context object.
Example: ``{'foo': 123}``
.. attr:: SimpleTemplateResponse.rendered_content:
The current rendered value of the response content, using the current
template and context data.
.. attr:: SimpleTemplateResponse.is_rendered:
A boolean indicating whether the response content has been rendered.
Methods
-------
.. method:: SimpleTemplateResponse.__init__(template, context=None, mimetype=None, status=None, content_type=None)
Instantiates an
:class:`~django.template.response.SimpleTemplateResponse` object
with the given template, context, MIME type and HTTP status.
``template`` is a full name of a template, or a sequence of
template names. :class:`django.template.Template` instances can
also be used.
``context`` is a dictionary of values to add to the template
context. By default, this is an empty dictionary.
:class:`~django.template.Context` objects are also accepted as
``context`` values.
``status`` is the HTTP Status code for the response.
``content_type`` is an alias for ``mimetype``. Historically, this
parameter was only called ``mimetype``, but since this is actually
the value included in the HTTP ``Content-Type`` header, it can
also include the character set encoding, which makes it more than
just a MIME type specification. If ``mimetype`` is specified (not
``None``), that value is used. Otherwise, ``content_type`` is
used. If neither is given, the ``DEFAULT_CONTENT_TYPE`` setting is
used.
.. method:: SimpleTemplateResponse.resolve_context(context)
Converts context data into a context instance that can be used for
rendering a template. Accepts a dictionary of context data or a
context object. Returns a :class:`~django.template.Context`
instance containing the provided data.
Override this method in order to customize context instantiation.
.. method:: SimpleTemplateResponse.resolve_template(template)
Resolves the template instance to use for rendering. Accepts a
path of a template to use, or a sequence of template paths.
:class:`~django.template.Template` instances may also be provided.
Returns the :class:`~django.template.Template` instance to be
rendered.
Override this method in order to customize template rendering.
.. method:: SimpleTemplateResponse.render():
Sets :attr:`response.content` to the result obtained by
:attr:`SimpleTemplateResponse.rendered_content`.
:meth:`~SimpleTemplateResponse.render()` will only have an effect
the first time it is called. On subsequent calls, it will return
the result obtained from the first call.
.. class:: TemplateResponse()
TemplateResponse is a subclass of :class:`SimpleTemplateResponse
<django.template.response.SimpleTemplateResponse>` that uses
RequestContext instead of Context.
.. method:: TemplateResponse.__init__(request, template, context=None, mimetype=None, status=None, content_type=None)
Instantiates an ``TemplateResponse`` object with the given
template, context, MIME type and HTTP status.
``request`` is a HttpRequest instance.
``template`` is a full name of a template to use or sequence of
template names. :class:`django.template.Template` instances are
also accepted.
``context`` is a dictionary of values to add to the template
context. By default, this is an empty dictionary; context objects
are also accepted as ``context`` values.
``status`` is the HTTP Status code for the response.
``content_type`` is an alias for ``mimetype``. Historically, this
parameter was only called ``mimetype``, but since this is actually
the value included in the HTTP ``Content-Type`` header, it can also
include the character set encoding, which makes it more than just a
MIME type specification. If ``mimetype`` is specified (not
``None``), that value is used. Otherwise, ``content_type`` is used.
If neither is given, the ``DEFAULT_CONTENT_TYPE`` setting is used.
The rendering process
=====================
Before a :class:`TemplateResponse()` instance can be returned to the
client, it must be rendered. The rendering process takes the
intermediate representation of template and context, and turns it into
the final byte stream that can be served to the client.
There are three circumstances under which a TemplateResponse will be
rendered:
* When the TemplateResponse instance is explicitly rendered, using
the :meth:`SimpleTemplateResponse.render()` method.
* When the content of the response is explicitly set by assigning
:attr:`response.content`.
* After passing through template response middleware, but before
passing through response middleware.
A TemplateResponse can only be rendered once. The first call to
:meth:`SimpleTemplateResponse.render()` sets the content of the
response; subsequent rendering calls do not change the response
content.
However, when :attr:`response.content` is explicitly assigned, the
change is always applied. If you want to force the content to be
re-rendered, you can re-evaluate the rendered content, and assign
the content of the response manually::
# Set up a baked TemplateResponse
>>> t = TemplateResponse(request, 'original.html', {})
>>> t.render()
>>> print t.content
Original content
# Rebaking doesn't change content
>>> t.template_name = 'new.html'
>>> t.render()
>>> print t.content
Original content
# Assigning content does change, no render() call required
>>> t.content = t.rendered_content
>>> print t.content
New content
Using TemplateResponse and SimpleTemplateResponse
=================================================
A TemplateResponse object can be used anywhere that a normal
HttpResponse can be used. It can also be used as an alternative to
calling :method:`~django.shortcuts.render_to_response()`.
For example, the following simple view returns a
:class:`TemplateResponse()` with a simple template, and a context
containing a queryset::
from django.template.response import TemplateResponse
def blog_index(request):
return TemplateResponse(request, 'entry_list.html', {'entries': Entry.objects.all()})

View File

@ -133,6 +133,27 @@ can also add special translator comments in the source.
For more information, see :ref:`contextual-markers` and
:ref:`translator-comments`.
TemplateResponse
~~~~~~~~~~~~~~~~
It can sometimes be beneficial to allow decorators or middleware to
modify a response *after* it has been constructed by the view. For
example, you may want to change the template that is used, or put
additional data into the context.
However, you can't (easily) modify the content of a basic
:class:`~django.http.HttpResponse` after it has been constructed. To
overcome this limitation, Django 1.3 adds a new
:class:`~django.template.TemplateResponse` class. Unlike basic
:class:`~django.http.HttpResponse` objects,
:class:`~django.template.TemplateResponse` objects retain the details
of the template and context that was provided by the view to compute
the response. The final output of the response is not computed until
it is needed, later in the response process.
For more details, see the :ref:`documentation </ref/template-response>`
on the :class:`~django.template.TemplateResponse` class.
Everything else
~~~~~~~~~~~~~~~

View File

@ -97,6 +97,39 @@ calling ANY other request, view or exception middleware, or the appropriate
view; it'll return that :class:`~django.http.HttpResponse`. Response
middleware is always called on every response.
.. _template-response-middleware:
``process_template_response``
-----------------------------
.. versionadded:: 1.3
.. method:: process_template_response(self, request, response)
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
:class:`~django.template.response.SimpleTemplateResponse` subclass (e.g.
:class:`~django.template.response.TemplateResponse`) object returned by a
Django view.
``process_template_response()`` must return an
:class:`~django.template.response.SimpleTemplateResponse` (or it's subclass)
object. It could alter the given ``response`` by changing
``response.template_name`` and ``response.template_context``, or it could
create and return a brand-new
:class:`~django.template.response.SimpleTemplateResponse` (or it's subclass)
instance.
``process_template_response()`` will only be called if the response
instance has a ``render()`` method, indicating that it is a
:class:`~django.template.response.TemplateResponse`.
You don't need to explicitly render responses -- responses will be
automatically rendered once all template response middleware has been
called.
Middleware are run in reverse order during the response phase, which
includes process_template_response.
.. _response-middleware:
``process_response``
@ -120,6 +153,7 @@ an earlier middleware method returned an :class:`~django.http.HttpResponse`
classes are applied in reverse order, from the bottom up. This means classes
defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first.
.. _exception-middleware:
``process_exception``
@ -137,7 +171,7 @@ Django calls ``process_exception()`` when a view raises an exception.
the browser. Otherwise, default exception handling kicks in.
Again, middleware are run in reverse order during the response phase, which
includes ``process_exception``. If an exception middleware return a response,
includes ``process_exception``. If an exception middleware returns a response,
the middleware classes above that middleware will not be called at all.
``__init__``

View File

@ -156,6 +156,7 @@ class TemplateViewTest(TestCase):
rf = RequestFactory()
def _assert_about(self, response):
response.render()
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, '<h1>About</h1>')

View File

@ -3,9 +3,10 @@ import sys
from django.conf import settings
from django.core.signals import got_request_exception
from django.http import HttpResponse
from django.template.response import TemplateResponse
from django.template import Template
from django.test import TestCase
class TestException(Exception):
pass
@ -16,6 +17,7 @@ class TestMiddleware(object):
self.process_request_called = False
self.process_view_called = False
self.process_response_called = False
self.process_template_response_called = False
self.process_exception_called = False
def process_request(self, request):
@ -24,6 +26,10 @@ class TestMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
self.process_view_called = True
def process_template_response(self, request, response):
self.process_template_response_called = True
return response
def process_response(self, request, response):
self.process_response_called = True
return response
@ -48,6 +54,11 @@ class ResponseMiddleware(TestMiddleware):
super(ResponseMiddleware, self).process_response(request, response)
return HttpResponse('Response Middleware')
class TemplateResponseMiddleware(TestMiddleware):
def process_template_response(self, request, response):
super(TemplateResponseMiddleware, self).process_template_response(request, response)
return TemplateResponse(request, Template('Template Response Middleware'))
class ExceptionMiddleware(TestMiddleware):
def process_exception(self, request, exception):
super(ExceptionMiddleware, self).process_exception(request, exception)
@ -66,6 +77,11 @@ class BadViewMiddleware(TestMiddleware):
super(BadViewMiddleware, self).process_view(request, view_func, view_args, view_kwargs)
raise TestException('Test View Exception')
class BadTemplateResponseMiddleware(TestMiddleware):
def process_template_response(self, request, response):
super(BadTemplateResponseMiddleware, self).process_template_response(request, response)
raise TestException('Test Template Response Exception')
class BadResponseMiddleware(TestMiddleware):
def process_response(self, request, response):
super(BadResponseMiddleware, self).process_response(request, response)
@ -93,6 +109,7 @@ class BaseMiddlewareExceptionTest(TestCase):
def _add_middleware(self, middleware):
self.client.handler._request_middleware.insert(0, middleware.process_request)
self.client.handler._view_middleware.insert(0, middleware.process_view)
self.client.handler._template_response_middleware.append(middleware.process_template_response)
self.client.handler._response_middleware.append(middleware.process_response)
self.client.handler._exception_middleware.append(middleware.process_exception)
@ -113,9 +130,10 @@ class BaseMiddlewareExceptionTest(TestCase):
exception, value, tb = self.exceptions[i]
self.assertEquals(value.args, (error, ))
def assert_middleware_usage(self, middleware, request, view, response, exception):
def assert_middleware_usage(self, middleware, request, view, template_response, response, exception):
self.assertEqual(middleware.process_request_called, request)
self.assertEqual(middleware.process_view_called, view)
self.assertEqual(middleware.process_template_response_called, template_response)
self.assertEqual(middleware.process_response_called, response)
self.assertEqual(middleware.process_exception_called, exception)
@ -132,9 +150,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_middleware(self):
pre_middleware = TestMiddleware()
@ -146,9 +164,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_middleware(self):
pre_middleware = TestMiddleware()
@ -160,9 +178,23 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_template_response_middleware(self):
pre_middleware = TestMiddleware()
middleware = TemplateResponseMiddleware()
post_middleware = TestMiddleware()
self._add_middleware(post_middleware)
self._add_middleware(middleware)
self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/template_response/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, True, False)
def test_process_exception_middleware(self):
pre_middleware = TestMiddleware()
@ -174,9 +206,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_request_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -188,9 +220,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -202,9 +234,23 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_template_response_middleware_not_found(self):
pre_middleware = TestMiddleware()
middleware = TemplateResponseMiddleware()
post_middleware = TestMiddleware()
self._add_middleware(post_middleware)
self._add_middleware(middleware)
self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, True)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_response_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -216,9 +262,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, True)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, True)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -230,9 +276,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_request_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -244,9 +290,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -258,9 +304,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -272,9 +318,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', ['Error in view'], Exception())
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, True)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, True)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -286,9 +332,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_request_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -300,9 +346,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -314,9 +360,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -331,9 +377,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
ValueError())
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_exception_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -348,9 +394,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
ValueError())
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_request_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -362,9 +408,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -376,9 +422,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -390,9 +436,9 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, True)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, True)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -404,9 +450,18 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_template_response_error(self):
middleware = TestMiddleware()
self._add_middleware(middleware)
self.assert_exceptions_handled('/middleware_exceptions/template_response_error/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(middleware, True, True, True, True, False)
class BadMiddlewareTests(BaseMiddlewareExceptionTest):
@ -420,9 +475,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test Request Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_bad_middleware(self):
pre_middleware = TestMiddleware()
@ -434,9 +489,23 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test View Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_template_response_bad_middleware(self):
pre_middleware = TestMiddleware()
bad_middleware = BadTemplateResponseMiddleware()
post_middleware = TestMiddleware()
self._add_middleware(post_middleware)
self._add_middleware(bad_middleware)
self._add_middleware(pre_middleware)
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)
def test_process_response_bad_middleware(self):
pre_middleware = TestMiddleware()
@ -448,9 +517,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test Response Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, False, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_exception_bad_middleware(self):
pre_middleware = TestMiddleware()
@ -462,9 +531,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/view/', [])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_request_bad_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -476,9 +545,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Request Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_bad_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -490,9 +559,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test View Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_bad_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -504,9 +573,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Response Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, False, True)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_bad_middleware_not_found(self):
pre_middleware = TestMiddleware()
@ -518,9 +587,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Exception Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_request_bad_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -532,9 +601,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test Request Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_bad_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -546,9 +615,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test View Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_bad_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -560,9 +629,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', ['Error in view', 'Test Response Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, False, True)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_bad_middleware_exception(self):
pre_middleware = TestMiddleware()
@ -574,9 +643,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test Exception Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_request_bad_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -588,9 +657,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/null_view/', ['Test Request Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_bad_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -602,9 +671,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/null_view/', ['Test View Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_bad_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -619,9 +688,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, False, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_exception_bad_middleware_null_view(self):
pre_middleware = TestMiddleware()
@ -636,9 +705,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
ValueError())
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, True, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, True, False, True, False)
def test_process_request_bad_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -650,9 +719,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Request Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, True, False)
self.assert_middleware_usage(pre_middleware, True, False, False, True, False)
self.assert_middleware_usage(bad_middleware, True, False, False, True, False)
self.assert_middleware_usage(post_middleware, False, False, False, True, False)
def test_process_view_bad_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -664,9 +733,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test View Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, False)
self.assert_middleware_usage(post_middleware, True, False, True, False)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, False)
self.assert_middleware_usage(post_middleware, True, False, False, True, False)
def test_process_response_bad_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -678,9 +747,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Response Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, False, True)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
def test_process_exception_bad_middleware_permission_denied(self):
pre_middleware = TestMiddleware()
@ -692,9 +761,9 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Exception Exception'])
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, True, False)
self.assert_middleware_usage(bad_middleware, True, True, True, True)
self.assert_middleware_usage(post_middleware, True, True, True, True)
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
self.assert_middleware_usage(bad_middleware, True, True, False, True, True)
self.assert_middleware_usage(post_middleware, True, True, False, True, True)
_missing = object()

View File

@ -9,4 +9,7 @@ urlpatterns = patterns('',
(r'^error/$', views.server_error),
(r'^null_view/$', views.null_view),
(r'^permission_denied/$', views.permission_denied),
(r'^template_response/$', views.template_response),
(r'^template_response_error/$', views.template_response_error),
)

View File

@ -1,9 +1,18 @@
from django import http
from django.core.exceptions import PermissionDenied
from django.template import Template
from django.template.response import TemplateResponse
def normal_view(request):
return http.HttpResponse('OK')
def template_response(request):
return TemplateResponse(request, Template('OK'))
def template_response_error(request):
return TemplateResponse(request, Template('{%'))
def not_found(request):
raise http.Http404()

View File

@ -0,0 +1,174 @@
import os
from django.utils import unittest
from django.test import RequestFactory
from django.conf import settings
import django.template.context
from django.template import Template, Context, RequestContext
from django.template.response import (TemplateResponse, SimpleTemplateResponse,
ContentNotRenderedError)
def test_processor(request):
return {'processors': 'yes'}
test_processor_name = 'regressiontests.templates.response.test_processor'
class BaseTemplateResponseTest(unittest.TestCase):
# tests rely on fact that global context
# processors should only work when RequestContext is used.
def setUp(self):
self.factory = RequestFactory()
self._old_processors = settings.TEMPLATE_CONTEXT_PROCESSORS
self._old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
settings.TEMPLATE_CONTEXT_PROCESSORS = [test_processor_name]
settings.TEMPLATE_DIRS = (
os.path.join(
os.path.dirname(__file__),
'templates'
),
)
# Force re-evaluation of the contex processor list
django.template.context._standard_context_processors = None
def tearDown(self):
settings.TEMPLATE_DIRS = self._old_TEMPLATE_DIRS
settings.TEMPLATE_CONTEXT_PROCESSORS = self._old_processors
# Force re-evaluation of the contex processor list
django.template.context._standard_context_processors = None
class SimpleTemplateResponseTest(BaseTemplateResponseTest):
def _response(self, template='foo', *args, **kwargs):
return SimpleTemplateResponse(Template(template), *args, **kwargs)
def test_template_resolving(self):
response = SimpleTemplateResponse('first/test.html')
response.render()
self.assertEqual('First template\n', response.content)
templates = ['foo.html', 'second/test.html', 'first/test.html']
response = SimpleTemplateResponse(templates)
response.render()
self.assertEqual('Second template\n', response.content)
response = self._response()
response.render()
self.assertEqual(response.content, 'foo')
def test_explicit_baking(self):
# explicit baking
response = self._response()
self.assertFalse(response.is_rendered)
response.render()
self.assertTrue(response.is_rendered)
def test_render(self):
# response is not re-rendered without the render call
response = self._response().render()
self.assertEqual(response.content, 'foo')
# rebaking doesn't change the rendered content
response.template_name = Template('bar{{ baz }}')
response.render()
self.assertEqual(response.content, 'foo')
# but rendered content can be overridden by manually
# setting content
response.content = 'bar'
self.assertEqual(response.content, 'bar')
def test_iteration_unrendered(self):
# unrendered response raises an exception on iteration
response = self._response()
self.assertFalse(response.is_rendered)
def iteration():
for x in response:
pass
self.assertRaises(ContentNotRenderedError, iteration)
self.assertFalse(response.is_rendered)
def test_iteration_rendered(self):
# iteration works for rendered responses
response = self._response().render()
res = [x for x in response]
self.assertEqual(res, ['foo'])
def test_content_access_unrendered(self):
# unrendered response raises an exception when content is accessed
response = self._response()
self.assertFalse(response.is_rendered)
self.assertRaises(ContentNotRenderedError, lambda: response.content)
self.assertFalse(response.is_rendered)
def test_content_access_rendered(self):
# rendered response content can be accessed
response = self._response().render()
self.assertEqual(response.content, 'foo')
def test_set_content(self):
# content can be overriden
response = self._response()
self.assertFalse(response.is_rendered)
response.content = 'spam'
self.assertTrue(response.is_rendered)
self.assertEqual(response.content, 'spam')
response.content = 'baz'
self.assertEqual(response.content, 'baz')
def test_dict_context(self):
response = self._response('{{ foo }}{{ processors }}',
{'foo': 'bar'})
self.assertEqual(response.context_data, {'foo': 'bar'})
response.render()
self.assertEqual(response.content, 'bar')
def test_context_instance(self):
response = self._response('{{ foo }}{{ processors }}',
Context({'foo': 'bar'}))
self.assertEqual(response.context_data.__class__, Context)
response.render()
self.assertEqual(response.content, 'bar')
def test_kwargs(self):
response = self._response(content_type = 'application/json', status=504)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)
def test_args(self):
response = SimpleTemplateResponse('', {}, 'application/json', 504)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)
class TemplateResponseTest(BaseTemplateResponseTest):
def _response(self, template='foo', *args, **kwargs):
return TemplateResponse(self.factory.get('/'), Template(template),
*args, **kwargs)
def test_render(self):
response = self._response('{{ foo }}{{ processors }}').render()
self.assertEqual(response.content, 'yes')
def test_render_with_requestcontext(self):
response = self._response('{{ foo }}{{ processors }}',
{'foo': 'bar'}).render()
self.assertEqual(response.content, 'baryes')
def test_render_with_context(self):
response = self._response('{{ foo }}{{ processors }}',
Context({'foo': 'bar'})).render()
self.assertEqual(response.content, 'bar')
def test_kwargs(self):
response = self._response(content_type = 'application/json',
status=504)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)
def test_args(self):
response = TemplateResponse(self.factory.get('/'), '', {},
'application/json', 504)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)

View File

@ -28,6 +28,7 @@ from parser import ParserTests
from unicode import UnicodeTests
from nodelist import NodelistTest
from smartif import *
from response import *
try:
from loaders import *

View File

@ -0,0 +1 @@
{{ foo }}.{{ bar }}.{{ baz }}.{{ processors }}