Commit cc4effba authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

[1.8.x] Set context.template instead of context.engine while rendering.

This opens more possibilities, like accessing context.template.origin.

It also follows the chain of objects instead of following a shortcut.

Backport of 1bfcc950 from master
parent 84e7fec8
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -202,19 +202,19 @@ class Template(object):

    def render(self, context):
        "Display stage -- can be called many times"
        # Set engine attribute here to avoid changing the signature of either
        # Context.__init__ or Node.render. The engine is set only on the first
        # call to render. Further calls e.g. for includes don't override it.
        toplevel_render = context.engine is None
        # Set context.template to the original template -- as opposed to
        # extended or included templates -- during rendering. This may be
        # used for accessing context.template.engine.
        toplevel_render = context.template is None
        if toplevel_render:
            context.engine = self.engine
            context.template = self
        context.render_context.push()
        try:
            return self._render(context)
        finally:
            context.render_context.pop()
            if toplevel_render:
                context.engine = None
                context.template = None


class Token(object):
@@ -653,7 +653,7 @@ class FilterExpression(object):
                if ignore_failures:
                    obj = None
                else:
                    string_if_invalid = context.engine.string_if_invalid
                    string_if_invalid = context.template.engine.string_if_invalid
                    if string_if_invalid:
                        if '%s' in string_if_invalid:
                            return string_if_invalid % self.var
@@ -845,7 +845,7 @@ class Variable(object):
                    if getattr(current, 'do_not_call_in_templates', False):
                        pass
                    elif getattr(current, 'alters_data', False):
                        current = context.engine.string_if_invalid
                        current = context.template.engine.string_if_invalid
                    else:
                        try:  # method call (assuming no args required)
                            current = current()
@@ -853,12 +853,12 @@ class Variable(object):
                            try:
                                getcallargs(current)
                            except TypeError:  # arguments *were* required
                                current = context.engine.string_if_invalid  # invalid method call
                                current = context.template.engine.string_if_invalid  # invalid method call
                            else:
                                raise
        except Exception as e:
            if getattr(e, 'silent_variable_failure', False):
                current = context.engine.string_if_invalid
                current = context.template.engine.string_if_invalid
            else:
                raise

@@ -1275,9 +1275,9 @@ class Library(object):
                        elif isinstance(getattr(file_name, 'template', None), Template):
                            t = file_name.template
                        elif not isinstance(file_name, six.string_types) and is_iterable(file_name):
                            t = context.engine.select_template(file_name)
                            t = context.template.engine.select_template(file_name)
                        else:
                            t = context.engine.get_template(file_name)
                            t = context.template.engine.get_template(file_name)
                        self.nodelist = t.nodelist
                    new_context = context.new(_dict)
                    # Copy across the CSRF token, if present, because
+19 −13
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ class Context(BaseContext):
    "A stack container for variable context"
    def __init__(self, dict_=None, autoescape=True,
            current_app=_current_app_undefined,
            use_l10n=None, use_tz=None, engine=None):
            use_l10n=None, use_tz=None):
        if current_app is not _current_app_undefined:
            warnings.warn(
                "The current_app argument of Context is deprecated. Use "
@@ -133,8 +133,10 @@ class Context(BaseContext):
        self._current_app = current_app
        self.use_l10n = use_l10n
        self.use_tz = use_tz
        self.engine = engine
        self.render_context = RenderContext()
        # Set to the original template during rendering -- as opposed to
        # extended or included templates
        self.template = None
        super(Context, self).__init__(dict_)

    @property
@@ -192,11 +194,11 @@ class RequestContext(Context):
    """
    def __init__(self, request, dict_=None, processors=None,
            current_app=_current_app_undefined,
            use_l10n=None, use_tz=None, engine=None):
            use_l10n=None, use_tz=None):
        # current_app isn't passed here to avoid triggering the deprecation
        # warning in Context.__init__.
        super(RequestContext, self).__init__(
            dict_, use_l10n=use_l10n, use_tz=use_tz, engine=engine)
            dict_, use_l10n=use_l10n, use_tz=use_tz)
        if current_app is not _current_app_undefined:
            warnings.warn(
                "The current_app argument of RequestContext is deprecated. "
@@ -207,23 +209,27 @@ class RequestContext(Context):
        self._processors = () if processors is None else tuple(processors)
        self._processors_index = len(self.dicts)
        self.update({})         # placeholder for context processors output
        self.engine = engine    # re-run the setter in case engine is not None

    @property
    def engine(self):
        return self._engine

    @engine.setter
    def engine(self, engine):
        self._engine = engine
    def template(self):
        return self._template

    @template.setter
    def template(self, template):
        # Execute context processors when Template.render(self, context) sets
        # context.template = self. Until then, since the context isn't tied to
        # an engine, it has no way to know which context processors to apply.
        self._template = template
        if hasattr(self, '_processors_index'):
            if engine is None:
            if template is None:
                # Unset context processors.
                self.dicts[self._processors_index] = {}
            else:
                # Set context processors for this engine.
                processors = (template.engine.template_context_processors +
                              self._processors)
                updates = {}
                for processor in engine.template_context_processors + self._processors:
                for processor in processors:
                    updates.update(processor(self.request))
                self.dicts[self._processors_index] = updates

+3 −3
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ class ForNode(Node):
                    context[self.loopvars[0]] = item
                # In debug mode provide the source of the node which raised
                # the exception
                if context.engine.debug:
                if context.template.engine.debug:
                    for node in self.nodelist_loop:
                        try:
                            nodelist.append(node.render(context))
@@ -392,7 +392,7 @@ class SsiNode(Node):
    def render(self, context):
        filepath = self.filepath.resolve(context)

        if not include_is_allowed(filepath, context.engine.allowed_include_roots):
        if not include_is_allowed(filepath, context.template.engine.allowed_include_roots):
            if settings.DEBUG:
                return "[Didn't have permission to include file]"
            else:
@@ -404,7 +404,7 @@ class SsiNode(Node):
            output = ''
        if self.parsed:
            try:
                t = Template(output, name=filepath, engine=context.engine)
                t = Template(output, name=filepath, engine=context.template.engine)
                return t.render(context)
            except TemplateSyntaxError as e:
                if settings.DEBUG:
+3 −3
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ class ExtendsNode(Node):
        if isinstance(getattr(parent, 'template', None), Template):
            # parent is a django.template.backends.django.Template
            return parent.template
        return context.engine.get_template(parent)
        return context.template.engine.get_template(parent)

    def render(self, context):
        compiled_parent = self.get_parent(context)
@@ -148,7 +148,7 @@ class IncludeNode(Node):
            # Does this quack like a Template?
            if not callable(getattr(template, 'render', None)):
                # If not, we'll try get_template
                template = context.engine.get_template(template)
                template = context.template.engine.get_template(template)
            values = {
                name: var.resolve(context)
                for name, var in six.iteritems(self.extra_context)
@@ -158,7 +158,7 @@ class IncludeNode(Node):
            with context.push(**values):
                return template.render(context)
        except Exception:
            if context.engine.debug:
            if context.template.engine.debug:
                raise
            return ''

+1 −1
Original line number Diff line number Diff line
@@ -149,7 +149,7 @@ class BlockTranslateNode(Node):
                result = translation.pgettext(message_context, singular)
            else:
                result = translation.ugettext(singular)
        default_value = context.engine.string_if_invalid
        default_value = context.template.engine.string_if_invalid

        def render_value(key):
            if key in context:
Loading