Commit 79deb6a0 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Accounted for multiple template engines in template responses.

parent a3e783fe
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ from django.contrib import messages
from django.core.urlresolvers import reverse
from django import forms
from django.http import HttpResponseRedirect, HttpResponse
from django.template import RequestContext, Template
from django.template import engines
from django.template.response import TemplateResponse
from django.views.decorators.cache import never_cache
from django.contrib.messages.views import SuccessMessageMixin
@@ -48,13 +48,14 @@ def add_template_response(request, message_type):

@never_cache
def show(request):
    t = Template(TEMPLATE)
    return HttpResponse(t.render(RequestContext(request)))
    template = engines['django'].from_string(TEMPLATE)
    return HttpResponse(template.render(request=request))


@never_cache
def show_template_response(request):
    return TemplateResponse(request, Template(TEMPLATE))
    template = engines['django'].from_string(TEMPLATE)
    return TemplateResponse(request, template)


class ContactForm(forms.Form):
+61 −32
Original line number Diff line number Diff line
import warnings

from django.http import HttpResponse
from django.template import loader, Context, RequestContext
from django.template import loader, Context, RequestContext, Template
from django.template.backends.django import Template as BackendTemplate
from django.template.context import _current_app_undefined
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
@@ -16,14 +17,30 @@ class SimpleTemplateResponse(HttpResponse):

    def __init__(self, template, context=None, content_type=None, status=None,
                 charset=None):
        if isinstance(template, Template):
            warnings.warn(
                "{}'s template argument cannot be a django.template.Template "
                "anymore. It may be a backend-specific template like those "
                "created by get_template().".format(self.__class__.__name__),
                RemovedInDjango20Warning, stacklevel=2)
            template = BackendTemplate(template)

        # 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
        # API. To avoid the name collision, we use different names.
        self.template_name = template
        self.context_data = context

        self._post_render_callbacks = []

        # _request stores the current request object in subclasses that know
        # about requests, like TemplateResponse. It's defined in the base class
        # to minimize code duplication.
        # It's called self._request because self.request gets overwritten by
        # django.test.client.Client. Unlike template_name and context_data,
        # _request should not be considered part of the public API.
        self._request = None

        # 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.
@@ -62,14 +79,45 @@ class SimpleTemplateResponse(HttpResponse):
        else:
            return template

    def _resolve_template(self, template):
        # This wrapper deprecates returning a django.template.Template in
        # subclasses that override resolve_template. It can be removed in
        # Django 2.0.
        new_template = self.resolve_template(template)
        if isinstance(new_template, Template):
            warnings.warn(
                "{}.resolve_template() must return a backend-specific "
                "template like those created by get_template(), not a "
                "{}.".format(
                    self.__class__.__name__, new_template.__class__.__name__),
                RemovedInDjango20Warning, stacklevel=2)
            new_template = BackendTemplate(new_template)
        return new_template

    def resolve_context(self, context):
        """Converts 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)

    def _resolve_context(self, context):
        # This wrapper deprecates returning a Context or a RequestContext in
        # subclasses that override resolve_context. It can be removed in
        # Django 2.0. If returning a Context or a RequestContext works by
        # accident, it won't be an issue per se, but it won't be officially
        # supported either.
        new_context = self.resolve_context(context)
        if isinstance(new_context, RequestContext) and self._request is None:
            self._request = new_context.request
        if isinstance(new_context, Context):
            warnings.warn(
                "{}.resolve_context() must return a dict, not a {}.".format(
                    self.__class__.__name__, new_context.__class__.__name__),
                RemovedInDjango20Warning, stacklevel=2)
            # It would be tempting to do new_context = new_context.flatten()
            # here but that would cause template context processors to run for
            # TemplateResponse(request, template, Context({})), which would be
            # backwards-incompatible. As a consequence another deprecation
            # warning will be raised when rendering the template. There isn't
            # much we can do about that.
        return new_context

    @property
    def rendered_content(self):
@@ -80,14 +128,9 @@ class SimpleTemplateResponse(HttpResponse):
        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)
        # TODO - remove this hack - makes the tests pass until the next commit
        try:
            template = template.template
        except AttributeError:
            pass
        content = template.render(context)
        template = self._resolve_template(self.template_name)
        context = self._resolve_context(self.context_data)
        content = template.render(context, self._request)
        return content

    def add_post_render_callback(self, callback):
@@ -147,10 +190,6 @@ class TemplateResponse(SimpleTemplateResponse):

    def __init__(self, request, template, context=None, content_type=None,
            status=None, current_app=_current_app_undefined, charset=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
        # As a convenience we'll allow callers to provide current_app without
        # having to avoid needing to create the RequestContext directly
        if current_app is not _current_app_undefined:
@@ -161,14 +200,4 @@ class TemplateResponse(SimpleTemplateResponse):
            request.current_app = current_app
        super(TemplateResponse, self).__init__(
            template, context, content_type, status, charset)

    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
        context_instance = RequestContext(self._request)
        if context:
            context_instance.push(context)
        return context_instance
        self._request = request
+5 −0
Original line number Diff line number Diff line
@@ -114,6 +114,11 @@ details on these changes.
  :class:`~django.template.Context` in their
  :meth:`~django.template.backends.base.Template.render()` method anymore.

* :doc:`Template response APIs </ref/template-response>` will enforce the use
  of :class:`dict` and backend-dependent template objects instead of
  :class:`~django.template.Context` and :class:`~django.template.Template`
  respectively.

* The ``current_app`` parameter for the following function and classes will be
  removed:

+87 −45
Original line number Diff line number Diff line
@@ -31,19 +31,28 @@ Attributes

.. attribute:: SimpleTemplateResponse.template_name

    The name of the template to be rendered. Accepts a
    :class:`~django.template.Template` object, a path to a template or list
    of template paths.
    The name of the template to be rendered. Accepts a backend-dependent
    template object (such as those returned by
    :func:`~django.template.loader.get_template()`), the name of a template,
    or a list of template names.

    Example: ``['foo.html', 'path/to/bar.html']``

    .. deprecated:: 1.8

        ``template_name`` used to accept a :class:`~django.template.Template`.

.. attribute:: SimpleTemplateResponse.context_data

    The context data to be used when rendering the template. It can be
    a dictionary or a context object.
    The context data to be used when rendering the template. It must be a
    :class:`dict`.

    Example: ``{'foo': 123}``

    .. deprecated:: 1.8

        ``context_data`` used to accept a :class:`~django.template.Context`.

.. attribute:: SimpleTemplateResponse.rendered_content

    The current rendered value of the response content, using the current
@@ -58,21 +67,26 @@ Methods

.. method:: SimpleTemplateResponse.__init__(template, context=None, content_type=None, status=None, charset=None)

    Instantiates a
    :class:`~django.template.response.SimpleTemplateResponse` object
    with the given template, context, content type, and HTTP status.
    Instantiates a :class:`~django.template.response.SimpleTemplateResponse`
    object with the given template, context, content type, HTTP status, and
    charset.

    ``template``
        The full name of a template, or a sequence of template names.
        :class:`~django.template.Template` instances can also be used.
        A backend-dependent template object (such as those returned by
        :func:`~django.template.loader.get_template()`), the name of a template,
        or a list of template names.

        .. deprecated:: 1.8

            ``template`` used to accept a :class:`~django.template.Template`.

    ``context``
        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.
        A :class:`dict` of values to add to the template context. By default,
        this is an empty dictionary.

    ``status``
        The HTTP Status code for the response.
        .. deprecated:: 1.8

            ``context`` used to accept a :class:`~django.template.Context`.

    ``content_type``
        The value included in the HTTP ``Content-Type`` header, including the
@@ -80,6 +94,9 @@ Methods
        ``content_type`` is specified, then its value is used. Otherwise,
        :setting:`DEFAULT_CONTENT_TYPE` is used.

    ``status``
        The HTTP status code for the response.

    ``charset``
        The charset in which the response will be encoded. If not given it will
        be extracted from ``content_type``, and if that is unsuccessful, the
@@ -91,22 +108,42 @@ Methods

.. 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.
    Preprocesses context data that will be used for rendering a template.
    Accepts a :class:`dict` of context data. By default, returns the same
    :class:`dict`.

    Override this method in order to customize the context.

    Override this method in order to customize context instantiation.
    .. versionchanged:: 1.8

        ``resolve_context`` returns a :class:`dict`. It used to return a
        :class:`~django.template.Context`.

    .. deprecated:: 1.8

        ``resolve_context`` no longer accepts a
        :class:`~django.template.Context`.

.. 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.
    backend-dependent template object (such as those returned by
    :func:`~django.template.loader.get_template()`), the name of a template,
    or a list of template names.

    Returns the backend-dependent template object instance to be rendered.

    Override this method in order to customize template loading.

    .. versionchanged:: 1.8

        ``resolve_template`` returns backend-dependent template object. It
        used to return a :class:`~django.template.Template`.

    .. deprecated:: 1.8

    Override this method in order to customize template rendering.
        ``resolve_template`` no longer accepts a
        :class:`~django.template.Template`.

.. method:: SimpleTemplateResponse.add_post_render_callback()

@@ -142,34 +179,37 @@ TemplateResponse objects
.. class:: TemplateResponse()

    ``TemplateResponse`` is a subclass of
    :class:`~django.template.response.SimpleTemplateResponse` that uses
    a :class:`~django.template.RequestContext` instead of
    a :class:`~django.template.Context`.
    :class:`~django.template.response.SimpleTemplateResponse` that knows about
    the current :class:`~django.http.HttpRequest`.

Methods
-------

.. method:: TemplateResponse.__init__(request, template, context=None, content_type=None, status=None, current_app=None, charset=None)

    Instantiates an ``TemplateResponse`` object with the given
    template, context, MIME type and HTTP status.
    Instantiates a :class:`~django.template.response.TemplateResponse` object
    with the given request, template, context, content type, HTTP status, and
    charset.

    ``request``
        An :class:`~django.http.HttpRequest` instance.

    ``template``
        The full name of a template, or a sequence of template names.
        :class:`~django.template.Template` instances can also be used.
        A backend-dependent template object (such as those returned by
        :func:`~django.template.loader.get_template()`), the name of a template,
        or a list of template names.

        .. deprecated:: 1.8

            ``template`` used to accept a :class:`~django.template.Template`.

    ``context``
        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. If you pass a
        :class:`~django.template.Context` instance or subclass, it will be used
        instead of creating a new :class:`~django.template.RequestContext`.
        A :class:`dict` of values to add to the template context. By default,
        this is an empty dictionary.

    ``status``
        The HTTP Status code for the response.
        .. deprecated:: 1.8

            ``context`` used to accept a :class:`~django.template.Context`.

    ``content_type``
        The value included in the HTTP ``Content-Type`` header, including the
@@ -177,6 +217,9 @@ Methods
        ``content_type`` is specified, then its value is used. Otherwise,
        :setting:`DEFAULT_CONTENT_TYPE` is used.

    ``status``
        The HTTP status code for the response.

    ``current_app``
        A hint indicating which application contains the current view. See the
        :ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`
@@ -292,14 +335,13 @@ invoked immediately.
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
:func:`~django.shortcuts.render()` or
A :class:`TemplateResponse` object can be used anywhere that a normal
:class:`django.http.HttpResponse` can be used. It can also be used as an
alternative to calling :func:`~django.shortcuts.render()` or
:func:`~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::
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

+15 −0
Original line number Diff line number Diff line
@@ -1397,6 +1397,21 @@ Since it's easier to understand with examples, the :ref:`upgrade guide

All this also applies to :func:`~django.template.loader.select_template()`.

:class:`~django.template.Template` and :class:`~django.template.Context` classes in template responses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some methods of :class:`~django.template.response.SimpleTemplateResponse` and
:class:`~django.template.response.TemplateResponse` accepted
:class:`django.template.Context` and :class:`django.template.Template` objects
as arguments. They should now receive :class:`dict` and backend-dependent
template objects respectively.

This also applies to the return types if you have subclassed either template
response class.

Check the :doc:`template response API documentation </ref/template-response>`
for details.

``current_app`` argument of template-related APIs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Loading