Commit 5c63c455 authored by Tim Graham's avatar Tim Graham
Browse files

[1.8.x] Fixed #23441, #24555 -- Improved the behavior of InclusionNode.

This change:

* Makes the InclusionNode cache-safe by removing render-time side effects
  to its nodelist.
* Ensures the render_context stack is properly scoped and reset by updating
  the render call to use Template.render rather than Nodelist.render.

Backport of 0808ccce from master
parent ff8eabc5
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -1262,10 +1262,16 @@ class Library(object):
            class InclusionNode(TagHelperNode):

                def render(self, context):
                    """
                    Renders the specified template and context. Caches the
                    template object in render_context to avoid reparsing and
                    loading when used in a for loop.
                    """
                    resolved_args, resolved_kwargs = self.get_resolved_arguments(context)
                    _dict = func(*resolved_args, **resolved_kwargs)

                    if not getattr(self, 'nodelist', False):
                    t = context.render_context.get(self)
                    if t is None:
                        if isinstance(file_name, Template):
                            t = file_name
                        elif isinstance(getattr(file_name, 'template', None), Template):
@@ -1274,7 +1280,7 @@ class Library(object):
                            t = context.template.engine.select_template(file_name)
                        else:
                            t = context.template.engine.get_template(file_name)
                        self.nodelist = t.nodelist
                        context.render_context[self] = t
                    new_context = context.new(_dict)
                    # Copy across the CSRF token, if present, because
                    # inclusion tags are often used for forms, and we need
@@ -1283,7 +1289,7 @@ class Library(object):
                    csrf_token = context.get('csrf_token', None)
                    if csrf_token is not None:
                        new_context['csrf_token'] = csrf_token
                    return self.nodelist.render(new_context)
                    return t.render(new_context)

            function_name = (name or
                getattr(func, '_decorated_function', func).__name__)
+1 −0
Original line number Diff line number Diff line
{% block content %}base{% endblock %}
+2 −0
Original line number Diff line number Diff line
{% extends 'inclusion_base.html' %}
{% block content %}one{% endblock %}
+2 −0
Original line number Diff line number Diff line
{% extends 'inclusion_base.html' %}
{% block content %}two{% endblock %}
+10 −0
Original line number Diff line number Diff line
@@ -164,3 +164,13 @@ def inclusion_tag_without_context_parameter(arg):
    """Expected inclusion_tag_without_context_parameter __doc__"""
    return {}
inclusion_tag_without_context_parameter.anything = "Expected inclusion_tag_without_context_parameter __dict__"


@register.inclusion_tag('inclusion_extends1.html')
def inclusion_extends1():
    return {}


@register.inclusion_tag('inclusion_extends2.html')
def inclusion_extends2():
    return {}
Loading