Ticket #12816: render_shortcut.6.diff

File render_shortcut.6.diff, 77.3 KB (added by kmike, 5 years ago)

force_bake is removed, template response middleware is introduces, exception is raised on content access for unbaked responses, more tests and some docs

  • django/contrib/messages/middleware.py

    diff -r 8343c0d86151 django/contrib/messages/middleware.py
    a b  
    11from django.conf import settings
    22from django.contrib.messages.storage import default_storage
    33
    4 
    54class MessageMiddleware(object):
    65    """
    76    Middleware that handles temporary messages.
  • django/contrib/messages/tests/base.py

    diff -r 8343c0d86151 django/contrib/messages/tests/base.py
    a b  
    9696        storage = self.get_storage()
    9797        self.assertFalse(storage.added_new)
    9898        storage.add(constants.INFO, 'Test message 1')
    99         self.assert_(storage.added_new)
     99        self.assertTrue(storage.added_new)
    100100        storage.add(constants.INFO, 'Test message 2', extra_tags='tag')
    101101        self.assertEqual(len(storage), 2)
    102102
     
    173173            for msg in data['messages']:
    174174                self.assertContains(response, msg)
    175175
     176    def test_with_template_response(self):
     177        settings.MESSAGE_LEVEL = constants.DEBUG
     178        data = {
     179            'messages': ['Test message %d' % x for x in xrange(10)],
     180        }
     181        show_url = reverse(self.urls + '.show_template_response')
     182
     183        for level in self.levels.keys():
     184            add_url = reverse(self.urls + '.add_template_response',
     185                              args=(level,))
     186            response = self.client.post(add_url, data, follow=True)
     187            self.assertRedirects(response, show_url)
     188            self.assertTrue('messages' in response.context)
     189            for msg in data['messages']:
     190                self.assertContains(response, msg)
     191
     192            # there shouldn't be any messages on second GET request
     193            response = self.client.get(show_url)
     194            for msg in data['messages']:
     195                self.assertNotContains(response, msg)
     196
    176197    def test_multiple_posts(self):
    177198        """
    178199        Tests that messages persist properly when multiple POSTs are made
  • django/contrib/messages/tests/urls.py

    diff -r 8343c0d86151 django/contrib/messages/tests/urls.py
    a b  
    22from django.contrib import messages
    33from django.core.urlresolvers import reverse
    44from django.http import HttpResponseRedirect, HttpResponse
    5 from django.shortcuts import render_to_response
     5from django.shortcuts import render_to_response, redirect
    66from django.template import RequestContext, Template
     7from django.template.response import TemplateResponse
    78
     9TEMPLATE = """{% if messages %}
     10<ul class="messages">
     11    {% for message in messages %}
     12    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
     13        {{ message }}
     14    </li>
     15    {% endfor %}
     16</ul>
     17{% endif %}
     18"""
    819
    920def add(request, message_type):
    1021    # don't default to False here, because we want to test that it defaults
     
    1627                                            fail_silently=fail_silently)
    1728        else:
    1829            getattr(messages, message_type)(request, msg)
     30
    1931    show_url = reverse('django.contrib.messages.tests.urls.show')
    2032    return HttpResponseRedirect(show_url)
    2133
     34def add_template_response(request, message_type):
     35    for msg in request.POST.getlist('messages'):
     36        getattr(messages, message_type)(request, msg)
     37    return redirect('django.contrib.messages.tests.urls.show_template_response')
    2238
    2339def show(request):
    24     t = Template("""{% if messages %}
    25 <ul class="messages">
    26     {% for message in messages %}
    27     <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
    28         {{ message }}
    29     </li>
    30     {% endfor %}
    31 </ul>
    32 {% endif %}""")
     40    t = Template(TEMPLATE)
    3341    return HttpResponse(t.render(RequestContext(request)))
    3442
     43def show_template_response(request):
     44    return TemplateResponse(request, Template(TEMPLATE))
    3545
    3646urlpatterns = patterns('',
    3747    ('^add/(debug|info|success|warning|error)/$', add),
    3848    ('^show/$', show),
     49    ('^add-template-response/(debug|info|success|warning|error)/$', add_template_response),
     50    ('^show-template-response/$', show_template_response),
    3951)
  • django/core/handlers/base.py

    diff -r 8343c0d86151 django/core/handlers/base.py
    a b  
    2121    def __init__(self):
    2222        self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
    2323
     24
    2425    def load_middleware(self):
    2526        """
    2627        Populate middleware lists from settings.MIDDLEWARE_CLASSES.
     
    3031        from django.conf import settings
    3132        from django.core import exceptions
    3233        self._view_middleware = []
     34        self._template_response_middleware = []
    3335        self._response_middleware = []
    3436        self._exception_middleware = []
    3537
    3638        request_middleware = []
    3739        for middleware_path in settings.MIDDLEWARE_CLASSES:
    3840            try:
    39                 dot = middleware_path.rindex('.')
    40             except ValueError:
    41                 raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path)
    42             mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
    43             try:
    44                 mod = import_module(mw_module)
    45             except ImportError, e:
    46                 raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
    47             try:
    48                 mw_class = getattr(mod, mw_classname)
    49             except AttributeError:
    50                 raise exceptions.ImproperlyConfigured('Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname))
    51 
    52             try:
    53                 mw_instance = mw_class()
     41                mw_instance = get_middleware_instance(middleware_path)
    5442            except exceptions.MiddlewareNotUsed:
    5543                continue
    5644
     
    5846                request_middleware.append(mw_instance.process_request)
    5947            if hasattr(mw_instance, 'process_view'):
    6048                self._view_middleware.append(mw_instance.process_view)
     49            if hasattr(mw_instance, 'process_template_response'):
     50                self._template_response_middleware.insert(0, mw_instance.process_template_response)
    6151            if hasattr(mw_instance, 'process_response'):
    6252                self._response_middleware.insert(0, mw_instance.process_response)
    6353            if hasattr(mw_instance, 'process_exception'):
     
    162152            urlresolvers.set_urlconf(None)
    163153
    164154        try:
     155            # Apply template response middleware and the bake the response
     156            # if the response can be baked
     157            if hasattr(response, 'bake') and callable(response.bake):
     158                for middleware_method in self._template_response_middleware:
     159                    response = middleware_method(request, response)
     160                response.bake()
     161
    165162            # Apply response middleware, regardless of the response
    166163            for middleware_method in self._response_middleware:
    167164                response = middleware_method(request, response)
     
    240237        return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
    241238    return force_unicode(environ.get('SCRIPT_NAME', u''))
    242239
     240def get_middleware_instance(middleware_path):
     241    """
     242    Returns middleware instance
     243    """
     244    try:
     245        dot = middleware_path.rindex('.')
     246    except ValueError:
     247        raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path)
     248    mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
     249    try:
     250        mod = import_module(mw_module)
     251    except ImportError, e:
     252        raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
     253    try:
     254        mw_class = getattr(mod, mw_classname)
     255    except AttributeError:
     256        raise exceptions.ImproperlyConfigured('Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname))
     257
     258    return mw_class()
     259
  • django/shortcuts/__init__.py

    diff -r 8343c0d86151 django/shortcuts/__init__.py
    a b  
    55"""
    66
    77from django.template import loader
     8from django.template.response import TemplateResponse
    89from django.http import HttpResponse, Http404
    910from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
    1011from django.db.models.manager import Manager
     
    2324    """
    2425    Returns an HttpResponseRedirect to the apropriate URL for the arguments
    2526    passed.
    26    
     27
    2728    The arguments could be:
    28    
     29
    2930        * A model: the model's `get_absolute_url()` function will be called.
    30    
     31
    3132        * A view name, possibly with arguments: `urlresolvers.reverse()` will
    3233          be used to reverse-resolve the name.
    33          
     34
    3435        * A URL, which will be used as-is for the redirect location.
    35        
     36
    3637    By default issues a temporary redirect; pass permanent=True to issue a
    3738    permanent redirect
    3839    """
     
    4041        redirect_class = HttpResponsePermanentRedirect
    4142    else:
    4243        redirect_class = HttpResponseRedirect
    43    
     44
    4445    # If it's a model, use get_absolute_url()
    4546    if hasattr(to, 'get_absolute_url'):
    4647        return redirect_class(to.get_absolute_url())
    47    
     48
    4849    # Next try a reverse URL resolution.
    4950    try:
    5051        return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs))
     
    5556        # If this doesn't "feel" like a URL, re-raise.
    5657        if '/' not in to and '.' not in to:
    5758            raise
    58        
     59
    5960    # Finally, fall back and assume it's a URL
    6061    return redirect_class(to)
    6162
     
    101102    obj_list = list(queryset.filter(*args, **kwargs))
    102103    if not obj_list:
    103104        raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
    104     return obj_list
    105  No newline at end of file
     105    return obj_list
     106
     107render = TemplateResponse
  • new file django/template/response.py

    diff -r 8343c0d86151 django/template/response.py
    - +  
     1from django.http import HttpResponse
     2from django.template import loader, Context, RequestContext
     3
     4class ContentNotReadyError(Exception):
     5    pass
     6
     7class SimpleTemplateResponse(HttpResponse):
     8
     9    def __init__(self, template, context=None, mimetype=None, status=None,
     10            content_type=None):
     11        # These two properties were originally called 'template' and 'context'
     12        # but django.test.client.Client was clobbering those leading to really
     13        # tricky-to-debug problems
     14        self.template_name = template
     15        self.template_context = context
     16        self.baked = False
     17
     18        # content argument doesn't make sense here because it will be replaced
     19        # with rendered template so we always pass empty string in order to
     20        # prevent errors and provide shorter signature.
     21        super(SimpleTemplateResponse, self).__init__('', mimetype, status,
     22                                                     content_type)
     23
     24    def resolve_template(self, template):
     25        "Accepts a template object, path-to-template or list of paths"
     26        if isinstance(template, (list, tuple)):
     27            return loader.select_template(template)
     28        elif isinstance(template, basestring):
     29            return loader.get_template(template)
     30        else:
     31            return template
     32
     33    def resolve_context(self, context):
     34        "context can be a dictionary or a context object"
     35        if isinstance(context, Context):
     36            return context
     37        else:
     38            return Context(context)
     39
     40    def render(self):
     41        template = self.resolve_template(self.template_name)
     42        context = self.resolve_context(self.template_context)
     43        content = template.render(context)
     44        return content
     45
     46    def bake(self):
     47        self._set_content(self.render())
     48        return self
     49
     50    def __iter__(self):
     51        if not self.baked:
     52            raise ContentNotReadyError('The response content is not ready. '
     53                                       'It must be baked before the iteration.')
     54        return super(SimpleTemplateResponse, self).__iter__()
     55
     56    def _get_content(self):
     57        if not self.baked:
     58            raise ContentNotReadyError('The response content is not ready. '
     59                                       'It must be baked before the first access.')
     60        return super(SimpleTemplateResponse, self)._get_content()
     61
     62    def _set_content(self, value):
     63        "Overrides rendered content, unless you later call bake()"
     64        super(SimpleTemplateResponse, self)._set_content(value)
     65        self.baked = True
     66
     67    content = property(_get_content, _set_content)
     68
     69class TemplateResponse(SimpleTemplateResponse):
     70
     71    def __init__(self, request, template, context=None, mimetype=None,
     72            status=None, content_type=None):
     73        # self.request gets over-written by django.test.client.Client - and
     74        # unlike template_context and template_name the _request should not
     75        # be considered part of the public API.
     76        self._request = request
     77        super(TemplateResponse, self).__init__(
     78            template, context, mimetype, status, content_type)
     79
     80    def resolve_context(self, context):
     81        if isinstance(context, Context):
     82            return context
     83        else:
     84            return RequestContext(self._request, context)
     85
     86def bake(response):
     87    """
     88    Bakes response if it can be baked. HttpResponse instances are unaffected.
     89    """
     90    if (hasattr(response, 'bake') and callable(response.bake)):
     91        response.bake()
  • django/test/testcases.py

    diff -r 8343c0d86151 django/test/testcases.py
    a b  
    484484        Asserts that the template with the provided name was used in rendering
    485485        the response.
    486486        """
     487
    487488        if msg_prefix:
    488489            msg_prefix += ": "
    489490
  • django/views/generic/base.py

    diff -r 8343c0d86151 django/views/generic/base.py
    a b  
    22from django import http
    33from django.core.exceptions import ImproperlyConfigured
    44from django.template import RequestContext, loader
     5from django.template.response import TemplateResponse
    56from django.utils.translation import ugettext_lazy as _
    67from django.utils.functional import update_wrapper
    78from django.utils.log import getLogger
     
    8889    A mixin that can be used to render a template.
    8990    """
    9091    template_name = None
     92    template_response_class = TemplateResponse
    9193
    92     def render_to_response(self, context):
     94    def render_to_response(self, context, **response_kwargs):
    9395        """
    9496        Returns a response with a template rendered with the given context.
    9597        """
    96         return self.get_response(self.render_template(context))
    97 
    98     def get_response(self, content, **httpresponse_kwargs):
    99         """
    100         Construct an `HttpResponse` object.
    101         """
    102         return http.HttpResponse(content, **httpresponse_kwargs)
    103 
    104     def render_template(self, context):
    105         """
    106         Render the template with a given context.
    107         """
    108         context_instance = self.get_context_instance(context)
    109         return self.get_template().render(context_instance)
    110 
    111     def get_context_instance(self, context):
    112         """
    113         Get the template context instance. Must return a Context (or subclass)
    114         instance.
    115         """
    116         return RequestContext(self.request, context)
    117 
    118     def get_template(self):
    119         """
    120         Get a ``Template`` object for the given request.
    121         """
    122         names = self.get_template_names()
    123         if not names:
    124             raise ImproperlyConfigured(u"'%s' must provide template_name."
    125                                        % self.__class__.__name__)
    126         return self.load_template(names)
     98        return self.template_response_class(
     99            request = self.request,
     100            template =  self.get_template_names(),
     101            context = context,
     102            **response_kwargs
     103        )
    127104
    128105    def get_template_names(self):
    129106        """
    130         Return a list of template names to be used for the request. Must return
    131         a list. May not be called if get_template is overridden.
     107        Returns a list of template names to be used for the request. Must return
     108        a list. May not be called if render_to_response is overridden.
    132109        """
    133110        if self.template_name is None:
    134111            return []
    135112        else:
    136113            return [self.template_name]
    137114
    138     def load_template(self, names):
    139         """
    140         Load a list of templates using the default template loader.
    141         """
    142         return loader.select_template(names)
    143 
    144115
    145116class TemplateView(TemplateResponseMixin, View):
    146117    """
  • docs/index.txt

    diff -r 8343c0d86151 docs/index.txt
    a b  
    9393      :doc:`View functions <topics/http/views>` |
    9494      :doc:`Shortcuts <topics/http/shortcuts>`
    9595
    96     * **Reference:**  :doc:`Request/response objects <ref/request-response>`
     96    * **Reference:**
     97      :doc:`Request/response objects <ref/request-response>` |
     98      :doc:`TemplateResponse <ref/template-response>`
    9799
    98100    * **File uploads:**
    99101      :doc:`Overview <topics/http/file-uploads>` |
  • docs/ref/class-based-views.txt

    diff -r 8343c0d86151 docs/ref/class-based-views.txt
    a b  
    7676
    7777        The path to the template to use when rendering the view.
    7878
    79     .. method:: render_to_response(context)
     79    .. attribute:: template_response_class
    8080
    81         Returns a full composed HttpResponse instance, ready to be returned to
    82         the user.
     81        The response class to be returned by ``render_to_response`` method.
     82        Default is
     83        :class:`TemplateResponse <django.template.response.TemplateResponse>`.
     84        The template and context of TemplateResponse instances can be
     85        altered later (e.g. in
     86        :ref:`template response middleware <template-response-middleware>`).
    8387
    84         Calls :meth:`~TemplateResponseMixin.render_template()` to build the
    85         content of the response, and
    86         :meth:`~TemplateResponseMixin.get_response()` to construct the
    87         :class:`~django.http.HttpResponse` object.
     88        Create TemplateResponse subclass and pass set it to
     89        ``template_response_class`` if you need custom template loading or
     90        custom context object instantiation.
    8891
    89     .. method:: get_response(content, **httpresponse_kwargs)
     92    .. method:: render_to_response(context, **response_kwargs)
    9093
    91         Constructs the :class:`~django.http.HttpResponse` object around the
    92         given content. If any keyword arguments are provided, they will be
    93         passed to the constructor of the :class:`~django.http.HttpResponse`
    94         instance.
     94        Returns a ``self.template_response_class`` instance.
    9595
    96     .. method:: render_template(context)
    97 
    98         Calls :meth:`~TemplateResponseMixin.get_context_instance()` to obtain
    99         the :class:`Context` instance to use for rendering, and calls
    100         :meth:`TemplateReponseMixin.get_template()` to load the template that
    101         will be used to render the final content.
    102 
    103     .. method:: get_context_instance(context)
    104 
    105         Turns the data dictionary ``context`` into an actual context instance
    106         that can be used for rendering.
    107 
    108         By default, constructs a :class:`~django.template.RequestContext`
    109         instance.
    110 
    111     .. method:: get_template()
     96        If any keyword arguments are provided, they will be
     97        passed to the constructor of the response instance.
    11298
    11399        Calls :meth:`~TemplateResponseMixin.get_template_names()` to obtain the
    114100        list of template names that will be searched looking for an existent
     
    123109        default implementation will return a list containing
    124110        :attr:`TemplateResponseMixin.template_name` (if it is specified).
    125111
    126     .. method:: load_template(names)
    127 
    128         Loads and returns a template found by searching the list of ``names``
    129         for a match. Uses Django's default template loader.
    130112
    131113Single object mixins
    132114--------------------
  • docs/ref/index.txt

    diff -r 8343c0d86151 docs/ref/index.txt
    a b  
    1616   middleware
    1717   models/index
    1818   request-response
     19   template-response
    1920   settings
    2021   signals
    2122   templates/index
  • docs/ref/request-response.txt

    diff -r 8343c0d86151 docs/ref/request-response.txt
    a b  
    645645.. class:: HttpResponseServerError
    646646
    647647    Acts just like :class:`HttpResponse` but uses a 500 status code.
     648
     649TemplateResponse
     650----------------
     651
     652.. versionadded:: 1.3
     653
     654See :doc:`TemplateResponse <ref/template-response>` for more.
  • new file docs/ref/template-response.txt

    diff -r 8343c0d86151 docs/ref/template-response.txt
    - +  
     1===========================================
     2TemplateResponse and SimpleTemplateResponse
     3===========================================
     4
     5.. versionadded:: 1.3
     6
     7.. module:: django.template.response
     8   :synopsis: Classes dealing with lazy-rendered HTTP responses.
     9
     10Quick overview
     11==============
     12
     13An HttpResponse with an opaque string as its content is hard to alter after
     14it is returned from a view.
     15
     16Special HttpResponse subclass - TemplateResponse is introduced in Django to
     17solve this problem. It can keep a template and its context separate until
     18the very last moment when response middleware is applied and only then do
     19render a template. Such lazy template rendering is called 'baking' throught
     20the docs.
     21
     22This way it is possible to add something to the view's context before it
     23blends in a template or to change the template that will be rendered.
     24
     25This document explains the APIs for :class:`SimpleTemplateResponse` and
     26:class:`TemplateResponse` objects.
     27
     28SimpleTemplateResponse objects
     29==============================
     30
     31.. class:: SimpleTemplateResponse()
     32
     33Attributes
     34----------
     35
     36.. attribute:: SimpleTemplateResponse.template_name
     37
     38    Template to be rendered. Accepts :class:`django.template.Template` object,
     39    path to template or list of paths.
     40
     41    Example: ``['foo.html', 'bar.html']``
     42
     43.. attribute:: SimpleTemplateResponse.template_context
     44
     45    Context to be used with template. It can be a dictionary or a context
     46    object.
     47
     48    Example: ``{'foo': 123}``
     49
     50
     51Methods
     52-------
     53
     54.. method:: SimpleTemplateResponse.__init__(template, context=None, mimetype=None, status=None, content_type=None)
     55
     56   Instantiates an ``SimpleTemplateResponse`` object with the given template,
     57   context, MIME type and HTTP status.
     58
     59   ``template`` is a full name of a template to use or sequence of
     60   template names. :class:`django.template.Template` instances are also
     61   accepted.
     62
     63   ``context`` is a dictionary of values to add to the template context.
     64   By default, this is an empty dictionary; context objects are also
     65   accepted as ``context`` values.
     66
     67   ``status`` is the HTTP Status code for the response.
     68
     69   ``content_type`` is an alias for ``mimetype``. Historically, this parameter
     70   was only called ``mimetype``, but since this is actually the value included
     71   in the HTTP ``Content-Type`` header, it can also include the character set
     72   encoding, which makes it more than just a MIME type specification.
     73   If ``mimetype`` is specified (not ``None``), that value is used.
     74   Otherwise, ``content_type`` is used. If neither is given, the
     75   ``DEFAULT_CONTENT_TYPE`` setting is used.
     76
     77
     78.. method:: SimpleTemplateResponse.resolve_context(context)
     79
     80   Accepts dictionary or a context object.
     81   Returns :class:`django.template.Context` instance.
     82
     83   Override this method in order to customize context instantiation.
     84
     85
     86.. method:: SimpleTemplateResponse.resolve_template(template)
     87
     88   Accepts a full name of a template to use or sequence of template names.
     89   :class:`django.template.Template` instances are also accepted.
     90   Returns :class:`django.template.Template` instance to be rendered.
     91
     92   Override this method in order to customize template rendering.
     93
     94.. method:: SimpleTemplateResponse.render():
     95
     96   Renders a template instance returned by
     97   :meth:`SimpleTemplateResponse.resolve_template` using the context instance
     98   returned by :meth:`SimpleTemplateResponse.resolve_context` and returns the
     99   rendered content.
     100
     101.. method:: SimpleTemplateResponse.bake():
     102
     103   Bakes the response by setting :attr:`response.content` to the result
     104   returned by :meth:`SimpleTemplateResponse.render`.
     105
     106   The response is baked by Django during response middleware cycle. You should
     107   only bake the response yourself if it is to be used outside the
     108   request-response cycle (e.g. for debugging). It will be baked twice
     109   otherwise.
     110
     111
     112
     113TemplateResponse objects
     114========================
     115
     116.. class:: TemplateResponse()
     117
     118   TemplateResponse is a subclass of
     119   :class:`SimpleTemplateResponse <django.template.response.SimpleTemplateResponse>`
     120   that uses RequestContext instead of Context.
     121
     122.. method:: TemplateResponse.__init__(request, template, context=None, mimetype=None, status=None, content_type=None)
     123
     124   Instantiates an ``TemplateResponse`` object with the given template,
     125   context, MIME type and HTTP status.
     126
     127   ``request`` is a HttpRequest instance.
     128
     129   ``template`` is a full name of a template to use or sequence of
     130   template names. :class:`django.template.Template` instances are also
     131   accepted.
     132
     133   ``context`` is a dictionary of values to add to the template context.
     134   By default, this is an empty dictionary; context objects are also accepted
     135   as ``context`` values.
     136
     137   ``status`` is the HTTP Status code for the response.
     138
     139   ``content_type`` is an alias for ``mimetype``. Historically, this parameter
     140   was only called ``mimetype``, but since this is actually the value included
     141   in the HTTP ``Content-Type`` header, it can also include the character set
     142   encoding, which makes it more than just a MIME type specification.
     143   If ``mimetype`` is specified (not ``None``), that value is used.
     144   Otherwise, ``content_type`` is used. If neither is given, the
     145   ``DEFAULT_CONTENT_TYPE`` setting is used.
     146
  • docs/topics/http/middleware.txt

    diff -r 8343c0d86151 docs/topics/http/middleware.txt
    a b  
    120120classes are applied in reverse order, from the bottom up. This means classes
    121121defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first.
    122122
     123.. _template-response-middleware:
     124
     125``process_template_response``
     126-----------------------------
     127
     128.. versionadded:: 1.3
     129
     130.. method:: process_template_response(self, request, response)
     131
     132``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
     133:class:`~django.template.response.SimpleTemplateResponse` subclass (e.g.
     134:class:`~django.template.response.TemplateResponse`) object returned by a
     135Django view.
     136
     137``process_template_response()`` must return an
     138:class:`~django.template.response.SimpleTemplateResponse` (or it's subclass)
     139object. It could alter the given ``response`` by changing
     140``response.template_name`` and ``response.template_context``, or it could
     141create and return a brand-new
     142:class:`~django.template.response.SimpleTemplateResponse` (or it's subclass)
     143instance.
     144
     145``process_template_response()`` method is called only on response instances that
     146can be baked. It is called before the ``process_response()`` method.
     147
     148You shouldn't bake the response in ``process_template_response``. It
     149will be baked just before applying response middlewares. This way template
     150will be rendered exactly 1 time.
     151
     152Middleware are run in reverse order during the response phase, which
     153includes process_template_response.
     154
    123155.. _exception-middleware:
    124156
    125157``process_exception``
  • docs/topics/http/shortcuts.txt

    diff -r 8343c0d86151 docs/topics/http/shortcuts.txt
    a b  
    1212"span" multiple levels of MVC. In other words, these functions/classes
    1313introduce controlled coupling for convenience's sake.
    1414
     15``render``
     16==========
     17
     18.. function:: render(request, template[, context][, mimetype][, status][, content_type])
     19
     20   Combines a given template with a given context dictionary and returns an
     21   :class:`~django.template.response.TemplateResponse` object.
     22
     23   TODO
     24
     25Examples
     26--------
     27
     28TODO
     29
     30
     31
    1532``render_to_response``
    1633======================
    1734
  • tests/regressiontests/generic_views/base.py

    diff -r 8343c0d86151 tests/regressiontests/generic_views/base.py
    a b  
    156156    rf = RequestFactory()
    157157
    158158    def _assert_about(self, response):
     159        response.bake()
    159160        self.assertEqual(response.status_code, 200)
    160161        self.assertEqual(response.content, '<h1>About</h1>')
    161162
  • tests/regressiontests/middleware_exceptions/tests.py

    diff -r 8343c0d86151 tests/regressiontests/middleware_exceptions/tests.py
    a b  
    33from django.test import TestCase
    44from django.core.signals import got_request_exception
    55from django.http import HttpResponse
    6 
     6from django.template.response import TemplateResponse
     7from django.template import Template
    78
    89class TestException(Exception):
    910    pass
     
    1516        self.process_request_called = False
    1617        self.process_view_called = False
    1718        self.process_response_called = False
     19        self.process_template_response_called = False
    1820        self.process_exception_called = False
    1921
    2022    def process_request(self, request):
     
    2325    def process_view(self, request, view_func, view_args, view_kwargs):
    2426        self.process_view_called = True
    2527
     28    def process_template_response(self, request, response):
     29        self.process_template_response_called = True
     30        return response
     31
    2632    def process_response(self, request, response):
    2733        self.process_response_called = True
    2834        return response
     
    4753        super(ResponseMiddleware, self).process_response(request, response)
    4854        return HttpResponse('Response Middleware')
    4955
     56class TemplateResponseMiddleware(TestMiddleware):
     57    def process_template_response(self, request, response):
     58        super(TemplateResponseMiddleware, self).process_template_response(request, response)
     59        return TemplateResponse(request, Template('Template Response Middleware'))
     60
    5061class ExceptionMiddleware(TestMiddleware):
    5162    def process_exception(self, request, exception):
    5263        super(ExceptionMiddleware, self).process_exception(request, exception)
     
    6576        super(BadViewMiddleware, self).process_view(request, view_func, view_args, view_kwargs)
    6677        raise TestException('Test View Exception')
    6778
     79class BadTemplateResponseMiddleware(TestMiddleware):
     80    def process_template_response(self, request, response):
     81        super(BadTemplateResponseMiddleware, self).process_template_response(request, response)
     82        raise TestException('Test Template Response Exception')
     83
    6884class BadResponseMiddleware(TestMiddleware):
    6985    def process_response(self, request, response):
    7086        super(BadResponseMiddleware, self).process_response(request, response)
     
    92108    def _add_middleware(self, middleware):
    93109        self.client.handler._request_middleware.insert(0, middleware.process_request)
    94110        self.client.handler._view_middleware.insert(0, middleware.process_view)
     111        self.client.handler._template_response_middleware.append(middleware.process_template_response)
    95112        self.client.handler._response_middleware.append(middleware.process_response)
    96113        self.client.handler._exception_middleware.append(middleware.process_exception)
    97114
     
    112129            exception, value, tb = self.exceptions[i]
    113130            self.assertEquals(value.args, (error, ))
    114131
    115     def assert_middleware_usage(self, middleware, request, view, response, exception):
     132    def assert_middleware_usage(self, middleware, request, view, template_response, response, exception):
    116133        self.assertEqual(middleware.process_request_called, request)
    117134        self.assertEqual(middleware.process_view_called, view)
     135        self.assertEqual(middleware.process_template_response_called, template_response)
    118136        self.assertEqual(middleware.process_response_called, response)
    119137        self.assertEqual(middleware.process_exception_called, exception)
    120138
     
    131149        self.assert_exceptions_handled('/middleware_exceptions/view/', [])
    132150
    133151        # Check that the right middleware methods have been invoked
    134         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    135         self.assert_middleware_usage(middleware,      True,  False, True,  False)
    136         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     152        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     153        self.assert_middleware_usage(middleware,      True,  False, False, True,  False)
     154        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    137155
    138156    def test_process_view_middleware(self):
    139157        pre_middleware = TestMiddleware()
     
    145163        self.assert_exceptions_handled('/middleware_exceptions/view/', [])
    146164
    147165        # Check that the right middleware methods have been invoked
    148         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    149         self.assert_middleware_usage(middleware,      True,  True, True, False)
    150         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     166        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     167        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     168        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    151169
    152170    def test_process_response_middleware(self):
    153171        pre_middleware = TestMiddleware()
     
    159177        self.assert_exceptions_handled('/middleware_exceptions/view/', [])
    160178
    161179        # Check that the right middleware methods have been invoked
    162         self.assert_middleware_usage(pre_middleware,  True,  True,  True,  False)
    163         self.assert_middleware_usage(middleware,      True,  True,  True,  False)
    164         self.assert_middleware_usage(post_middleware, True,  True,  True,  False)
     180        self.assert_middleware_usage(pre_middleware,  True,  True, False, True,  False)
     181        self.assert_middleware_usage(middleware,      True,  True, False, True,  False)
     182        self.assert_middleware_usage(post_middleware, True,  True, False, True,  False)
     183
     184    def test_process_template_response_middleware(self):
     185        pre_middleware = TestMiddleware()
     186        middleware = TemplateResponseMiddleware()
     187        post_middleware = TestMiddleware()
     188        self._add_middleware(post_middleware)
     189        self._add_middleware(middleware)
     190        self._add_middleware(pre_middleware)
     191        self.assert_exceptions_handled('/middleware_exceptions/template_response/', [])
     192
     193        # Check that the right middleware methods have been invoked
     194        self.assert_middleware_usage(pre_middleware,  True,  True, True, True,  False)
     195        self.assert_middleware_usage(middleware,      True,  True, True, True,  False)
     196        self.assert_middleware_usage(post_middleware, True,  True, True, True,  False)
    165197
    166198    def test_process_exception_middleware(self):
    167199        pre_middleware = TestMiddleware()
     
    173205        self.assert_exceptions_handled('/middleware_exceptions/view/', [])
    174206
    175207        # Check that the right middleware methods have been invoked
    176         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    177         self.assert_middleware_usage(middleware,      True,  True, True, False)
    178         self.assert_middleware_usage(post_middleware, True,  True, True, False)
     208        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     209        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     210        self.assert_middleware_usage(post_middleware, True,  True, False, True, False)
    179211
    180212    def test_process_request_middleware_not_found(self):
    181213        pre_middleware = TestMiddleware()
     
    187219        self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
    188220
    189221        # Check that the right middleware methods have been invoked
    190         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    191         self.assert_middleware_usage(middleware,      True,  False, True,  False)
    192         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     222        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     223        self.assert_middleware_usage(middleware,      True,  False, False, True,  False)
     224        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    193225
    194226    def test_process_view_middleware_not_found(self):
    195227        pre_middleware = TestMiddleware()
     
    201233        self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
    202234
    203235        # Check that the right middleware methods have been invoked
    204         self.assert_middleware_usage(pre_middleware,  True,  True,  True, False)
    205         self.assert_middleware_usage(middleware,      True,  True,  True, False)
    206         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     236        self.assert_middleware_usage(pre_middleware,  True,  True, False,  True, False)
     237        self.assert_middleware_usage(middleware,      True,  True, False,  True, False)
     238        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
     239
     240    def test_process_template_response_middleware_not_found(self):
     241        pre_middleware = TestMiddleware()
     242        middleware = TemplateResponseMiddleware()
     243        post_middleware = TestMiddleware()
     244        self._add_middleware(post_middleware)
     245        self._add_middleware(middleware)
     246        self._add_middleware(pre_middleware)
     247        self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
     248
     249        # Check that the right middleware methods have been invoked
     250        self.assert_middleware_usage(pre_middleware,  True,  True, False, True,  True)
     251        self.assert_middleware_usage(middleware,      True,  True, False, True,  True)
     252        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    207253
    208254    def test_process_response_middleware_not_found(self):
    209255        pre_middleware = TestMiddleware()
     
    215261        self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
    216262
    217263        # Check that the right middleware methods have been invoked
    218         self.assert_middleware_usage(pre_middleware,  True,  True, True,  True)
    219         self.assert_middleware_usage(middleware,      True,  True, True,  True)
    220         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     264        self.assert_middleware_usage(pre_middleware,  True,  True, False, True,  True)
     265        self.assert_middleware_usage(middleware,      True,  True, False, True,  True)
     266        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    221267
    222268    def test_process_exception_middleware_not_found(self):
    223269        pre_middleware = TestMiddleware()
     
    229275        self.assert_exceptions_handled('/middleware_exceptions/not_found/', [])
    230276
    231277        # Check that the right middleware methods have been invoked
    232         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    233         self.assert_middleware_usage(middleware,      True,  True,  True, True)
    234         self.assert_middleware_usage(post_middleware, True,  True,  True, True)
     278        self.assert_middleware_usage(pre_middleware,  True, True, False, True, False)
     279        self.assert_middleware_usage(middleware,      True, True, False, True, True)
     280        self.assert_middleware_usage(post_middleware, True, True, False, True, True)
    235281
    236282    def test_process_request_middleware_exception(self):
    237283        pre_middleware = TestMiddleware()
     
    243289        self.assert_exceptions_handled('/middleware_exceptions/error/', [])
    244290
    245291        # Check that the right middleware methods have been invoked
    246         self.assert_middleware_usage(pre_middleware,  True, False, True,  False)
    247         self.assert_middleware_usage(middleware,  True, False, True,  False)
    248         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     292        self.assert_middleware_usage(pre_middleware, True, False, False, True,  False)
     293        self.assert_middleware_usage(middleware,     True, False, False, True,  False)
     294        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    249295
    250296    def test_process_view_middleware_exception(self):
    251297        pre_middleware = TestMiddleware()
     
    257303        self.assert_exceptions_handled('/middleware_exceptions/error/', [])
    258304
    259305        # Check that the right middleware methods have been invoked
    260         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    261         self.assert_middleware_usage(middleware,      True,  True, True, False)
    262         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     306        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     307        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     308        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    263309
    264310    def test_process_response_middleware_exception(self):
    265311        pre_middleware = TestMiddleware()
     
    271317        self.assert_exceptions_handled('/middleware_exceptions/error/', ['Error in view'], Exception())
    272318
    273319        # Check that the right middleware methods have been invoked
    274         self.assert_middleware_usage(pre_middleware,  True,  True, True,  True)
    275         self.assert_middleware_usage(middleware,      True,  True, True,  True)
    276         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     320        self.assert_middleware_usage(pre_middleware,  True,  True, False, True,  True)
     321        self.assert_middleware_usage(middleware,      True,  True, False, True,  True)
     322        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    277323
    278324    def test_process_exception_middleware_exception(self):
    279325        pre_middleware = TestMiddleware()
     
    285331        self.assert_exceptions_handled('/middleware_exceptions/error/', [])
    286332
    287333        # Check that the right middleware methods have been invoked
    288         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    289         self.assert_middleware_usage(middleware,      True,  True, True,  True)
    290         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     334        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     335        self.assert_middleware_usage(middleware,      True,  True, False, True,  True)
     336        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    291337
    292338    def test_process_request_middleware_null_view(self):
    293339        pre_middleware = TestMiddleware()
     
    299345        self.assert_exceptions_handled('/middleware_exceptions/null_view/', [])
    300346
    301347        # Check that the right middleware methods have been invoked
    302         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    303         self.assert_middleware_usage(middleware,      True,  False, True,  False)
    304         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     348        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     349        self.assert_middleware_usage(middleware,      True,  False, False, True,  False)
     350        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    305351
    306352    def test_process_view_middleware_null_view(self):
    307353        pre_middleware = TestMiddleware()
     
    313359        self.assert_exceptions_handled('/middleware_exceptions/null_view/', [])
    314360
    315361        # Check that the right middleware methods have been invoked
    316         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    317         self.assert_middleware_usage(middleware,      True,  True, True, False)
    318         self.assert_middleware_usage(post_middleware, True, False, True, False)
     362        self.assert_middleware_usage(pre_middleware,  True, True, False, True, False)
     363        self.assert_middleware_usage(middleware,      True, True, False, True, False)
     364        self.assert_middleware_usage(post_middleware, True, False, False, True, False)
    319365
    320366    def test_process_response_middleware_null_view(self):
    321367        pre_middleware = TestMiddleware()
     
    330376            ValueError())
    331377
    332378        # Check that the right middleware methods have been invoked
    333         self.assert_middleware_usage(pre_middleware,  True,  True,  True, False)
    334         self.assert_middleware_usage(middleware,      True,  True,  True, False)
    335         self.assert_middleware_usage(post_middleware, True,  True,  True, False)
     379        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     380        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     381        self.assert_middleware_usage(post_middleware, True,  True, False, True, False)
    336382
    337383    def test_process_exception_middleware_null_view(self):
    338384        pre_middleware = TestMiddleware()
     
    347393            ValueError())
    348394
    349395        # Check that the right middleware methods have been invoked
    350         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    351         self.assert_middleware_usage(middleware,      True,  True, True, False)
    352         self.assert_middleware_usage(post_middleware, True,  True, True, False)
     396        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     397        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     398        self.assert_middleware_usage(post_middleware, True,  True, False, True, False)
    353399
    354400    def test_process_request_middleware_permission_denied(self):
    355401        pre_middleware = TestMiddleware()
     
    361407        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
    362408
    363409        # Check that the right middleware methods have been invoked
    364         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    365         self.assert_middleware_usage(middleware,      True,  False, True,  False)
    366         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     410        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     411        self.assert_middleware_usage(middleware,      True,  False, False, True,  False)
     412        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    367413
    368414    def test_process_view_middleware_permission_denied(self):
    369415        pre_middleware = TestMiddleware()
     
    375421        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
    376422
    377423        # Check that the right middleware methods have been invoked
    378         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    379         self.assert_middleware_usage(middleware,      True,  True, True, False)
    380         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     424        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     425        self.assert_middleware_usage(middleware,      True,  True, False, True, False)
     426        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    381427
    382428    def test_process_response_middleware_permission_denied(self):
    383429        pre_middleware = TestMiddleware()
     
    389435        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
    390436
    391437        # Check that the right middleware methods have been invoked
    392         self.assert_middleware_usage(pre_middleware,  True,  True, True,  True)
    393         self.assert_middleware_usage(middleware,      True,  True, True,  True)
    394         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     438        self.assert_middleware_usage(pre_middleware,  True,  True, False, True,  True)
     439        self.assert_middleware_usage(middleware,      True,  True, False, True,  True)
     440        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    395441
    396442    def test_process_exception_middleware_permission_denied(self):
    397443        pre_middleware = TestMiddleware()
     
    403449        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', [])
    404450
    405451        # Check that the right middleware methods have been invoked
    406         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    407         self.assert_middleware_usage(middleware,  True,  True, True,  True)
    408         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     452        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     453        self.assert_middleware_usage(middleware,  True,  True, False, True,  True)
     454        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    409455
    410456class BadMiddlewareTests(BaseMiddlewareExceptionTest):
    411457
     
    419465        self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test Request Exception'])
    420466
    421467        # Check that the right middleware methods have been invoked
    422         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    423         self.assert_middleware_usage(bad_middleware,  True,  False, True,  False)
    424         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     468        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     469        self.assert_middleware_usage(bad_middleware,  True,  False, False, True,  False)
     470        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    425471
    426472    def test_process_view_bad_middleware(self):
    427473        pre_middleware = TestMiddleware()
     
    433479        self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test View Exception'])
    434480
    435481        # Check that the right middleware methods have been invoked
    436         self.assert_middleware_usage(pre_middleware,  True,  True,  True, False)
    437         self.assert_middleware_usage(bad_middleware,  True,  True,  True, False)
    438         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     482        self.assert_middleware_usage(pre_middleware,  True,  True, False,  True, False)
     483        self.assert_middleware_usage(bad_middleware,  True,  True, False,  True, False)
     484        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
     485
     486    def test_process_template_response_bad_middleware(self):
     487        pre_middleware = TestMiddleware()
     488        bad_middleware = BadTemplateResponseMiddleware()
     489        post_middleware = TestMiddleware()
     490        self._add_middleware(post_middleware)
     491        self._add_middleware(bad_middleware)
     492        self._add_middleware(pre_middleware)
     493        self.assert_exceptions_handled('/middleware_exceptions/template_response/', ['Test Template Response Exception'])
     494
     495        # Check that the right middleware methods have been invoked
     496        self.assert_middleware_usage(pre_middleware,  True,  True, False,  False, False)
     497        self.assert_middleware_usage(bad_middleware,  True,  True, True,  False,  False)
     498        self.assert_middleware_usage(post_middleware, True,  True, True,  False,  False)
    439499
    440500    def test_process_response_bad_middleware(self):
    441501        pre_middleware = TestMiddleware()
     
    447507        self.assert_exceptions_handled('/middleware_exceptions/view/', ['Test Response Exception'])
    448508
    449509        # Check that the right middleware methods have been invoked
    450         self.assert_middleware_usage(pre_middleware,  True,  True, False, False)
    451         self.assert_middleware_usage(bad_middleware,  True,  True, True,  False)
    452         self.assert_middleware_usage(post_middleware, True,  True, True,  False)
     510        self.assert_middleware_usage(pre_middleware,  True,  True, False, False, False)
     511        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  False)
     512        self.assert_middleware_usage(post_middleware, True,  True, False, True,  False)
    453513
    454514    def test_process_exception_bad_middleware(self):
    455515        pre_middleware = TestMiddleware()
     
    461521        self.assert_exceptions_handled('/middleware_exceptions/view/', [])
    462522
    463523        # Check that the right middleware methods have been invoked
    464         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    465         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    466         self.assert_middleware_usage(post_middleware, True,  True, True, False)
     524        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     525        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     526        self.assert_middleware_usage(post_middleware, True,  True, False, True, False)
    467527
    468528    def test_process_request_bad_middleware_not_found(self):
    469529        pre_middleware = TestMiddleware()
     
    475535        self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Request Exception'])
    476536
    477537        # Check that the right middleware methods have been invoked
    478         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    479         self.assert_middleware_usage(bad_middleware,  True,  False, True,  False)
    480         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     538        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     539        self.assert_middleware_usage(bad_middleware,  True,  False, False, True,  False)
     540        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    481541
    482542    def test_process_view_bad_middleware_not_found(self):
    483543        pre_middleware = TestMiddleware()
     
    489549        self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test View Exception'])
    490550
    491551        # Check that the right middleware methods have been invoked
    492         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    493         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    494         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     552        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     553        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     554        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    495555
    496556    def test_process_response_bad_middleware_not_found(self):
    497557        pre_middleware = TestMiddleware()
     
    503563        self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Response Exception'])
    504564
    505565        # Check that the right middleware methods have been invoked
    506         self.assert_middleware_usage(pre_middleware,  True,  True, False, True)
    507         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    508         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     566        self.assert_middleware_usage(pre_middleware,  True,  True, False, False, True)
     567        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     568        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    509569
    510570    def test_process_exception_bad_middleware_not_found(self):
    511571        pre_middleware = TestMiddleware()
     
    517577        self.assert_exceptions_handled('/middleware_exceptions/not_found/', ['Test Exception Exception'])
    518578
    519579        # Check that the right middleware methods have been invoked
    520         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    521         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    522         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     580        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     581        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     582        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    523583
    524584    def test_process_request_bad_middleware_exception(self):
    525585        pre_middleware = TestMiddleware()
     
    531591        self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test Request Exception'])
    532592
    533593        # Check that the right middleware methods have been invoked
    534         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    535         self.assert_middleware_usage(bad_middleware,  True,  False, True,  False)
    536         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     594        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     595        self.assert_middleware_usage(bad_middleware,  True,  False, False, True,  False)
     596        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    537597
    538598    def test_process_view_bad_middleware_exception(self):
    539599        pre_middleware = TestMiddleware()
     
    545605        self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test View Exception'])
    546606
    547607        # Check that the right middleware methods have been invoked
    548         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    549         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    550         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     608        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     609        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     610        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    551611
    552612    def test_process_response_bad_middleware_exception(self):
    553613        pre_middleware = TestMiddleware()
     
    559619        self.assert_exceptions_handled('/middleware_exceptions/error/', ['Error in view', 'Test Response Exception'])
    560620
    561621        # Check that the right middleware methods have been invoked
    562         self.assert_middleware_usage(pre_middleware,  True,  True, False, True)
    563         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    564         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     622        self.assert_middleware_usage(pre_middleware,  True,  True, False, False, True)
     623        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     624        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    565625
    566626    def test_process_exception_bad_middleware_exception(self):
    567627        pre_middleware = TestMiddleware()
     
    573633        self.assert_exceptions_handled('/middleware_exceptions/error/', ['Test Exception Exception'])
    574634
    575635        # Check that the right middleware methods have been invoked
    576         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    577         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    578         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     636        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     637        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     638        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    579639
    580640    def test_process_request_bad_middleware_null_view(self):
    581641        pre_middleware = TestMiddleware()
     
    587647        self.assert_exceptions_handled('/middleware_exceptions/null_view/', ['Test Request Exception'])
    588648
    589649        # Check that the right middleware methods have been invoked
    590         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    591         self.assert_middleware_usage(bad_middleware,  True,  False, True,  False)
    592         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     650        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     651        self.assert_middleware_usage(bad_middleware,  True,  False, False, True,  False)
     652        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    593653
    594654    def test_process_view_bad_middleware_null_view(self):
    595655        pre_middleware = TestMiddleware()
     
    601661        self.assert_exceptions_handled('/middleware_exceptions/null_view/', ['Test View Exception'])
    602662
    603663        # Check that the right middleware methods have been invoked
    604         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    605         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    606         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     664        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     665        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     666        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    607667
    608668    def test_process_response_bad_middleware_null_view(self):
    609669        pre_middleware = TestMiddleware()
     
    618678            ])
    619679
    620680        # Check that the right middleware methods have been invoked
    621         self.assert_middleware_usage(pre_middleware,  True,  True, False, False)
    622         self.assert_middleware_usage(bad_middleware,  True,  True, True,  False)
    623         self.assert_middleware_usage(post_middleware, True,  True, True,  False)
     681        self.assert_middleware_usage(pre_middleware,  True,  True, False, False, False)
     682        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  False)
     683        self.assert_middleware_usage(post_middleware, True,  True, False, True,  False)
    624684
    625685    def test_process_exception_bad_middleware_null_view(self):
    626686        pre_middleware = TestMiddleware()
     
    635695            ValueError())
    636696
    637697        # Check that the right middleware methods have been invoked
    638         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    639         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    640         self.assert_middleware_usage(post_middleware, True,  True, True, False)
     698        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     699        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     700        self.assert_middleware_usage(post_middleware, True,  True, False, True, False)
    641701
    642702    def test_process_request_bad_middleware_permission_denied(self):
    643703        pre_middleware = TestMiddleware()
     
    649709        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Request Exception'])
    650710
    651711        # Check that the right middleware methods have been invoked
    652         self.assert_middleware_usage(pre_middleware,  True,  False, True,  False)
    653         self.assert_middleware_usage(bad_middleware,  True,  False, True,  False)
    654         self.assert_middleware_usage(post_middleware, False, False, True,  False)
     712        self.assert_middleware_usage(pre_middleware,  True,  False, False, True,  False)
     713        self.assert_middleware_usage(bad_middleware,  True,  False, False, True,  False)
     714        self.assert_middleware_usage(post_middleware, False, False, False, True,  False)
    655715
    656716    def test_process_view_bad_middleware_permission_denied(self):
    657717        pre_middleware = TestMiddleware()
     
    663723        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test View Exception'])
    664724
    665725        # Check that the right middleware methods have been invoked
    666         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    667         self.assert_middleware_usage(bad_middleware,  True,  True, True, False)
    668         self.assert_middleware_usage(post_middleware, True,  False, True, False)
     726        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     727        self.assert_middleware_usage(bad_middleware,  True,  True, False, True, False)
     728        self.assert_middleware_usage(post_middleware, True,  False, False, True, False)
    669729
    670730    def test_process_response_bad_middleware_permission_denied(self):
    671731        pre_middleware = TestMiddleware()
     
    677737        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Response Exception'])
    678738
    679739        # Check that the right middleware methods have been invoked
    680         self.assert_middleware_usage(pre_middleware,  True,  True, False, True)
    681         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    682         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     740        self.assert_middleware_usage(pre_middleware,  True,  True, False, False, True)
     741        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     742        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
    683743
    684744    def test_process_exception_bad_middleware_permission_denied(self):
    685745        pre_middleware = TestMiddleware()
     
    691751        self.assert_exceptions_handled('/middleware_exceptions/permission_denied/', ['Test Exception Exception'])
    692752
    693753        # Check that the right middleware methods have been invoked
    694         self.assert_middleware_usage(pre_middleware,  True,  True, True, False)
    695         self.assert_middleware_usage(bad_middleware,  True,  True, True,  True)
    696         self.assert_middleware_usage(post_middleware, True,  True, True,  True)
     754        self.assert_middleware_usage(pre_middleware,  True,  True, False, True, False)
     755        self.assert_middleware_usage(bad_middleware,  True,  True, False, True,  True)
     756        self.assert_middleware_usage(post_middleware, True,  True, False, True,  True)
  • tests/regressiontests/middleware_exceptions/urls.py

    diff -r 8343c0d86151 tests/regressiontests/middleware_exceptions/urls.py
    a b  
    99    (r'^error/$', views.server_error),
    1010    (r'^null_view/$', views.null_view),
    1111    (r'^permission_denied/$', views.permission_denied),
     12
     13    (r'^template_response/$', views.template_response),
     14    (r'^template_response_error/$', views.template_response_error),
    1215)
  • tests/regressiontests/middleware_exceptions/views.py

    diff -r 8343c0d86151 tests/regressiontests/middleware_exceptions/views.py
    a b  
    11from django import http
    22from django.core.exceptions import PermissionDenied
     3from django.shortcuts import render
     4from django.template import Template
    35
    46def normal_view(request):
    57    return http.HttpResponse('OK')
    68
     9def template_response(request):
     10    return render(request, Template('OK'))
     11
     12def template_response_error(request):
     13    return render(request, Template('{%'))
     14
    715def not_found(request):
    816    raise http.Http404()
    917
  • new file tests/regressiontests/templates/response.py

    diff -r 8343c0d86151 tests/regressiontests/templates/response.py
    - +  
     1import os
     2from django.utils import unittest
     3from django.test import RequestFactory
     4from django.conf import settings
     5import django.template.context
     6from django.template import Template, Context, RequestContext
     7from django.template.response import (TemplateResponse, SimpleTemplateResponse,
     8                                      ContentNotReadyError)
     9
     10def test_processor(request):
     11    return {'processors': 'yes'}
     12test_processor_name = 'regressiontests.templates.response.test_processor'
     13
     14class BaseTemplateResponseTest(unittest.TestCase):
     15    # tests rely on fact that global context
     16    # processors should only work when RequestContext is used.
     17
     18    def setUp(self):
     19        self.factory = RequestFactory()
     20        self._old_processors = settings.TEMPLATE_CONTEXT_PROCESSORS
     21        self._old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
     22        settings.TEMPLATE_CONTEXT_PROCESSORS = [test_processor_name]
     23        settings.TEMPLATE_DIRS = (
     24            os.path.join(
     25                os.path.dirname(__file__),
     26                'templates'
     27            ),
     28        )
     29        # Force re-evaluation of the contex processor list
     30        django.template.context._standard_context_processors = None
     31
     32    def tearDown(self):
     33        settings.TEMPLATE_DIRS = self._old_TEMPLATE_DIRS
     34        settings.TEMPLATE_CONTEXT_PROCESSORS = self._old_processors
     35        # Force re-evaluation of the contex processor list
     36        django.template.context._standard_context_processors = None
     37
     38
     39class SimpleTemplateResponseTest(BaseTemplateResponseTest):
     40
     41    def _response(self, template='foo', *args, **kwargs):
     42        return SimpleTemplateResponse(Template(template), *args, **kwargs)
     43
     44    def test_template_resolving(self):
     45        response = SimpleTemplateResponse('first/test.html')
     46        response.bake()
     47        self.assertEqual('First template\n', response.content)
     48
     49        templates = ['foo.html', 'second/test.html', 'first/test.html']
     50        response = SimpleTemplateResponse(templates)
     51        response.bake()
     52        self.assertEqual('Second template\n', response.content)
     53
     54        response = self._response()
     55        response.bake()
     56        self.assertEqual(response.content, 'foo')
     57
     58    def test_explicit_baking(self):
     59        # explicit baking
     60        response = self._response()
     61        self.assertFalse(response.baked)
     62        response.bake()
     63        self.assertTrue(response.baked)
     64
     65    def test_bake(self):
     66        # response is not re-baked without the bake call
     67        response = self._response().bake()
     68        self.assertEqual(response.content, 'foo')
     69
     70        response.template_name = Template('bar{{ baz }}')
     71        self.assertEqual(response.content, 'foo')
     72        response.bake()
     73        self.assertEqual(response.content, 'bar')
     74
     75        response.template_context = {'baz': 'baz'}
     76        self.assertEqual(response.content, 'bar')
     77        response.bake()
     78        self.assertEqual(response.content, 'barbaz')
     79
     80        response.template_context = {'baz': 'spam'}
     81        for x in response:
     82            pass
     83        self.assertEqual(response.content, 'barbaz')
     84
     85    def test_iteration_unbaked(self):
     86        # unbaked response raises an exception on iteration
     87        response = self._response()
     88        self.assertFalse(response.baked)
     89
     90        def iteration():
     91            for x in response:
     92                pass
     93        self.assertRaises(ContentNotReadyError, iteration)
     94        self.assertFalse(response.baked)
     95
     96    def test_iteration_baked(self):
     97        # iteration works for baked responses
     98        response = self._response().bake()
     99        res = [x for x in response]
     100        self.assertEqual(res, ['foo'])
     101
     102    def test_content_access_unbaked(self):
     103        # unbaked response raises an exception when content is accessed
     104        response = self._response()
     105        self.assertFalse(response.baked)
     106        self.assertRaises(ContentNotReadyError, lambda: response.content)
     107        self.assertFalse(response.baked)
     108
     109    def test_content_access_baked(self):
     110        # baked response content can be accessed
     111        response = self._response().bake()
     112        self.assertEqual(response.content, 'foo')
     113
     114    def test_set_content(self):
     115        # content can be overriden
     116        response = self._response()
     117        self.assertFalse(response.baked)
     118        response.content = 'spam'
     119        self.assertTrue(response.baked)
     120        self.assertEqual(response.content, 'spam')
     121        response.content = 'baz'
     122        self.assertEqual(response.content, 'baz')
     123
     124    def test_dict_context(self):
     125        response = self._response('{{ foo }}{{ processors }}',
     126                                  {'foo': 'bar'})
     127        self.assertEqual(response.template_context, {'foo': 'bar'})
     128        response.bake()
     129        self.assertEqual(response.content, 'bar')
     130
     131    def test_context_instance(self):
     132        response = self._response('{{ foo }}{{ processors }}',
     133                                  Context({'foo': 'bar'}))
     134        self.assertEqual(response.template_context.__class__, Context)
     135        response.bake()
     136        self.assertEqual(response.content, 'bar')
     137
     138    def test_kwargs(self):
     139        response = self._response(content_type = 'application/json', status=504)
     140        self.assertEqual(response['content-type'], 'application/json')
     141        self.assertEqual(response.status_code, 504)
     142
     143    def test_args(self):
     144        response = SimpleTemplateResponse('', {}, 'application/json', 504)
     145        self.assertEqual(response['content-type'], 'application/json')
     146        self.assertEqual(response.status_code, 504)
     147
     148
     149class TemplateResponseTest(BaseTemplateResponseTest):
     150
     151    def _response(self, template='foo', *args, **kwargs):
     152        return TemplateResponse(self.factory.get('/'), Template(template),
     153                                *args, **kwargs)
     154
     155    def test_render(self):
     156        response = self._response('{{ foo }}{{ processors }}').bake()
     157        self.assertEqual(response.content, 'yes')
     158
     159    def test_render_with_requestcontext(self):
     160        response = self._response('{{ foo }}{{ processors }}',
     161                                  {'foo': 'bar'}).bake()
     162        self.assertEqual(response.content, 'baryes')
     163
     164    def test_render_with_context(self):
     165        response = self._response('{{ foo }}{{ processors }}',
     166                                  Context({'foo': 'bar'})).bake()
     167        self.assertEqual(response.content, 'bar')
     168
     169    def test_kwargs(self):
     170        response = self._response(content_type = 'application/json',
     171                                  status=504)
     172        self.assertEqual(response['content-type'], 'application/json')
     173        self.assertEqual(response.status_code, 504)
     174
     175    def test_args(self):
     176        response = TemplateResponse(self.factory.get('/'), '', {},
     177                                    'application/json', 504)
     178        self.assertEqual(response['content-type'], 'application/json')
     179        self.assertEqual(response.status_code, 504)
  • tests/regressiontests/templates/tests.py

    diff -r 8343c0d86151 tests/regressiontests/templates/tests.py
    a b  
    2727from unicode import unicode_tests
    2828from nodelist import NodelistTest
    2929from smartif import *
     30from response import *
    3031
    3132try:
    3233    from loaders import *
  • new file tests/regressiontests/views/templates/debug/render_test.html

    diff -r 8343c0d86151 tests/regressiontests/views/templates/debug/render_test.html
    - +  
     1{{ foo }}.{{ bar }}.{{ baz }}.{{ processors }}
  • tests/regressiontests/views/tests/__init__.py

    diff -r 8343c0d86151 tests/regressiontests/views/tests/__init__.py
    a b  
    77from i18n import *
    88from specials import *
    99from static import *
     10from shortcuts import *
  • new file tests/regressiontests/views/tests/shortcuts.py

    diff -r 8343c0d86151 tests/regressiontests/views/tests/shortcuts.py
    - +  
     1from django.test import RequestFactory
     2from django.template import Template
     3from django.shortcuts import render
     4
     5from regressiontests.templates.response import BaseTemplateResponseTest
     6
     7def library_view(request):
     8    return render(request, 'debug/render_test.html',
     9                  {'foo': 'foo', 'baz': 'baz'})
     10
     11def customized_context_view(request):
     12    response = library_view(request)
     13    response.template_context.update({'bar': 'bar', 'baz': 'spam'})
     14    return response
     15
     16def customized_template_view(request):
     17    response = library_view(request)
     18    response.template_name = Template('context does not matter')
     19    return response
     20
     21
     22class RenderTest(BaseTemplateResponseTest):
     23
     24    def setUp(self):
     25        super(RenderTest, self).setUp()
     26        self.request = self.factory.get('/')
     27
     28    def test_library_view(self):
     29        response = library_view(self.request).bake()
     30        self.assertEqual(response.content, 'foo..baz.yes\n')
     31
     32    def test_customized_context(self):
     33        response = customized_context_view(self.request).bake()
     34        self.assertEqual(response.content, 'foo.bar.spam.yes\n')
     35
     36    def test_customized_template(self):
     37        response = customized_template_view(self.request).bake()
     38        self.assertEqual(response.content, 'context does not matter')
     39
     40    def test_status_and_content_type(self):
     41        response = render(self.request, 'base.html', {'foo': 'bar'},
     42                          'application/json', 504)
     43        self.assertEqual(response.status_code, 504)
     44        self.assertEqual(response['content-type'], 'application/json')
     45
Back to Top