Commit 90805b24 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Supported multiple template engines in render_to_string.

Adjusted its API through a deprecation path according to the DEP.
parent f9a6ebf6
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ This module collects helper functions and classes that "span" multiple levels
of MVC. In other words, these functions/classes introduce controlled coupling
for convenience's sake.
"""
import warnings

from django.template import loader, RequestContext
from django.http import HttpResponse, Http404
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
@@ -11,6 +13,7 @@ from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.core import urlresolvers
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning


def render_to_response(*args, **kwargs):
@@ -20,7 +23,12 @@ def render_to_response(*args, **kwargs):
    """
    httpresponse_kwargs = {'content_type': kwargs.pop('content_type', None)}

    return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
    # TODO: refactor to avoid the deprecated code path.
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", category=RemovedInDjango20Warning)
        content = loader.render_to_string(*args, **kwargs)

    return HttpResponse(content, **httpresponse_kwargs)


def render(request, *args, **kwargs):
@@ -45,8 +53,12 @@ def render(request, *args, **kwargs):

    kwargs['context_instance'] = context_instance

    return HttpResponse(loader.render_to_string(*args, **kwargs),
                        **httpresponse_kwargs)
    # TODO: refactor to avoid the deprecated code path.
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", category=RemovedInDjango20Warning)
        content = loader.render_to_string(*args, **kwargs)

    return HttpResponse(content, **httpresponse_kwargs)


def redirect(to, *args, **kwargs):
+27 −10
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ from .base import Context, Lexer, Parser, Template, TemplateDoesNotExist
from .context import _builtin_context_processors


_context_instance_undefined = object()
_dictionary_undefined = object()
_dirs_undefined = object()


@@ -165,14 +167,22 @@ class Engine(object):
            template = Template(template, origin, template_name, engine=self)
        return template

    def render_to_string(self, template_name, dictionary=None, context_instance=None,
                         dirs=_dirs_undefined):
    def render_to_string(self, template_name, context=None,
                         context_instance=_context_instance_undefined,
                         dirs=_dirs_undefined,
                         dictionary=_dictionary_undefined):
        """
        Loads the given template_name and renders it with the given dictionary as
        context. The template_name may be a string to load a single template using
        get_template, or it may be a tuple to use select_template to find one of
        the templates in the list. Returns a string.
        """
        if context_instance is _context_instance_undefined:
            context_instance = None
        else:
            warnings.warn(
                "The context_instance argument of render_to_string is "
                "deprecated.", RemovedInDjango20Warning, stacklevel=2)
        if dirs is _dirs_undefined:
            # Do not set dirs to None here to avoid triggering the deprecation
            # warning in select_template or get_template.
@@ -181,23 +191,30 @@ class Engine(object):
            warnings.warn(
                "The dirs argument of render_to_string is deprecated.",
                RemovedInDjango20Warning, stacklevel=2)
        if dictionary is _dictionary_undefined:
            dictionary = None
        else:
            warnings.warn(
                "The dictionary argument of render_to_string was renamed to "
                "context.", RemovedInDjango20Warning, stacklevel=2)
            context = dictionary

        if isinstance(template_name, (list, tuple)):
            t = self.select_template(template_name, dirs)
        else:
            t = self.get_template(template_name, dirs)
        if not context_instance:
            # Django < 1.8 accepted a Context in `dictionary` even though that's
            # unintended. Preserve this ability but don't rewrap `dictionary`.
            if isinstance(dictionary, Context):
                return t.render(dictionary)
            # Django < 1.8 accepted a Context in `context` even though that's
            # unintended. Preserve this ability but don't rewrap `context`.
            if isinstance(context, Context):
                return t.render(context)
            else:
                return t.render(Context(dictionary))
        if not dictionary:
                return t.render(Context(context))
        if not context:
            return t.render(context_instance)
        # Add the dictionary to the context stack, ensuring it gets removed again
        # Add the context to the context stack, ensuring it gets removed again
        # to keep the context_instance in the same state it started in.
        with context_instance.push(dictionary):
        with context_instance.push(context):
            return t.render(context_instance)

    def select_template(self, template_name_list, dirs=_dirs_undefined):
+57 −3
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@ from django.utils.deprecation import RemovedInDjango20Warning
from . import engines
from .backends.django import DjangoTemplates
from .base import Origin, TemplateDoesNotExist
from .engine import _dirs_undefined, Engine
from .engine import (
    _context_instance_undefined, _dictionary_undefined, _dirs_undefined)


class LoaderOrigin(Origin):
@@ -75,8 +76,61 @@ def select_template(template_name_list, dirs=_dirs_undefined, using=None):
        raise TemplateDoesNotExist("No template names provided")


def render_to_string(*args, **kwargs):
    return Engine.get_default().render_to_string(*args, **kwargs)
def render_to_string(template_name, context=None,
                     context_instance=_context_instance_undefined,
                     dirs=_dirs_undefined,
                     dictionary=_dictionary_undefined,
                     using=None):
    """
    Loads a template and renders it with a context. Returns a string.

    template_name may be a string or a list of strings.
    """
    if (context_instance is _context_instance_undefined
            and dirs is _dirs_undefined
            and dictionary is _dictionary_undefined):
        # No deprecated arguments were passed - use the new code path
        if isinstance(template_name, (list, tuple)):
            template = select_template(template_name, using=using)
        else:
            template = get_template(template_name, using=using)
        return template.render(context)

    else:
        # Some deprecated arguments were passed - use the legacy code path
        for engine in _engine_list(using):
            try:
                # This is required for deprecating arguments specific to Django
                # templates. Simply return engine.render_to_string(template_name,
                # context) in Django 2.0.
                if isinstance(engine, DjangoTemplates):
                    # Hack -- use the internal Engine instance of DjangoTemplates.
                    return engine.engine.render_to_string(
                        template_name, context, context_instance, dirs, dictionary)
                elif context_instance is not _context_instance_undefined:
                    warnings.warn(
                        "Skipping template backend %s because its render_to_string "
                        "method doesn't support the context_instance argument." %
                        engine.name, stacklevel=2)
                elif dirs is not _dirs_undefined:
                    warnings.warn(
                        "Skipping template backend %s because its render_to_string "
                        "method doesn't support the dirs argument." % engine.name,
                        stacklevel=2)
                elif dictionary is not _dictionary_undefined:
                    warnings.warn(
                        "Skipping template backend %s because its render_to_string "
                        "method doesn't support the dictionary argument." %
                        engine.name, stacklevel=2)
            except TemplateDoesNotExist:
                continue

        if template_name:
            if isinstance(template_name, (list, tuple)):
                template_name = ', '.join(template_name)
            raise TemplateDoesNotExist(template_name)
        else:
            raise TemplateDoesNotExist("No template names provided")


def _engine_list(using=None):
+5 −0
Original line number Diff line number Diff line
@@ -88,6 +88,11 @@ details on these changes.
* The backwards compatibility alias ``django.template.loader.BaseLoader`` will
  be removed.

* The ``dictionary`` and ``context_instance`` parameters for the following
  functions will be removed:

  * ``django.template.loader.render_to_string()``

* The ``dirs`` parameter for the following functions will be removed:

  * ``django.template.loader.get_template()``
+13 −4
Original line number Diff line number Diff line
@@ -890,7 +890,7 @@ When :setting:`TEMPLATE_DEBUG` is ``True`` template objects will have an
The ``render_to_string`` shortcut
===================================

.. function:: loader.render_to_string(template_name, dictionary=None, context_instance=None)
.. function:: loader.render_to_string(template_name, context=None, context_instance=None)

To cut down on the repetitive nature of loading and rendering
templates, Django provides a shortcut function which largely
@@ -906,16 +906,25 @@ The ``render_to_string`` shortcut takes one required argument --
and render (or a list of template names, in which case Django will use
the first template in the list that exists) -- and two optional arguments:

dictionary
``context``
    A dictionary to be used as variables and values for the
    template's context. This can also be passed as the second
    template's context. This should be passed as the second
    positional argument.

context_instance
    .. versionchanged:: 1.8

       The ``context`` argument used to be called ``dictionary``. That name
       is deprecated in Django 1.8 and will be removed in Django 2.0.

``context_instance``
    An instance of :class:`~django.template.Context` or a subclass (e.g., an
    instance of :class:`~django.template.RequestContext`) to use as the
    template's context. This can also be passed as the third positional argument.

    .. deprecated:: 1.8

       The ``context_instance`` argument is deprecated. Simply use ``context``.

See also the :func:`~django.shortcuts.render_to_response()` shortcut, which
calls ``render_to_string`` and feeds the result into an :class:`~django.http.HttpResponse`
suitable for returning directly from a view.
Loading