Search code examples
pythonjinja2

Context behavior for jinja2 blocks with included files


I have difficulties understanding the context behavior when including files in Jinja2 blocks. See this minimal example:

base.jinja2

{% set foo="bar" %}

{% block content %}
{% include 'include.jinja2' %}
{% endblock content %}

include.jinja2

{{ foo }}

Rendering base.jinja2 produces the error foo' is undefined.

When I move the declaration of foo into the content block, the code renders correctly. So does it, when I move the include statement outside the content block, when I remove the content block around the include statement, or when I replace the include statement with the file's contents.

Why is that? How can I use the global foo variable in the include file inside the content block?


Solution

  • Look at the link, section Block Nesting and Scope:

    Blocks can be nested for more complex layouts. However, per default blocks may not access variables from outer scopes: The reason for this is that if the block is replaced by a child template, a variable would appear that was not defined in the block or passed to the context.

    According to the document and starting with Jinja 2.2 you can change this behavior using scoped.

    {% set foo="bar" %}
    
    {% block content scoped %}
    {% include 'include.jinja2' %}
    {% endblock content %}
    
    

    I agree that this is somehow weird, compared to what we are used to. But this is an intended feature.

    Generally speaking, include is only passed the context. Since 2.1 it is passed a derived context that is the original context + all the local variables used before the include statement. This also means that if you just use a variable from an outer scope, Jinja2 will track it as local now and pass it to the derived context.