Skip to content

Using Namespace in Jinja Templates

In Jinja, the namespace object allows you to create mutable variables, enabling values to persist across iterations or conditions. This can be particularly useful in scenarios where you need to increment counters or maintain state during loops.

What is a Namespace?

A namespace is an object-like container in Jinja that allows attributes to be modified, unlike standard variables, which are immutable after being set.

Syntax

jinja
{% set variable = namespace(attribute=value) %}
  • variable is the namespace object.
  • attribute is a mutable key in the namespace.
  • value is the initial value assigned to the attribute.

Example: Counting Status Codes

Input Context

json
{
    "sub_instances_responses": [
        {"value": "{\"status\": 201}"},
        {"value": "{\"status\": 207}"},
        {"value": "{\"status\": 400}"},
        {"value": "{\"status\": 201}"},
        {"value": "{\"status\": 400}"}
    ]
}

Template

jinja
{% set Count400 = namespace(value=0) -%}
{% set Count201 = namespace(value=0) -%}
{% set Count207 = namespace(value=0) -%}


{% for rsp in sub_instances_responses -%}
    {% if (rsp['value'] | json).status == 201 -%}
        {% set Count201.value = Count201.value + 1 -%}
    {% elif (rsp['value'] | json).status == 207 -%}
        {% set Count207.value = Count207.value + 1 -%}
    {% elif (rsp['value'] | json).status == 400 -%}
        {% set Count400.value = Count400.value + 1 -%}
    {% endif -%}
{% endfor -%}


{
    "count201": {{ Count201.value }},
    "count207": {{ Count207.value }},
    "count400": {{ Count400.value }}
}

Output

json
{
    "count201": 2,
    "count207": 1,
    "count400": 2
}

Why Use Namespace?

Jinja variables are immutable. Once a variable is set, you cannot modify it directly. This limitation makes it impossible to increment counters or change values inside a loop without using a namespace.

Example of Template Without Namespace

jinja
{% set count201 = 0 -%}
{% for rsp in sub_instances_responses -%}
    {% if (rsp['value'] | json).status == 201 -%}
        {% set count201 = count201 + 1 -%}  {# Error: count201 is immutable! -#}
    {% endif -%}
{% endfor -%}
{{count201}}

The output will be wrong: it will be 0 instead of 2

Are Namespaces always necessary?

Namespaces are only required when:

  • You need to modify a variable multiple times, such as incrementing a counter in a loop.
  • You are working with complex data that requires mutable attributes.

Alternatives to Namespace

For simpler cases, you can often restructure your template to avoid the need for namespaces. For example, you can use loops to aggregate data into a list or dictionary, and then process it afterward.

Example Without Namespace

jinja
{% set counts = {"201": 0, "207": 0, "400": 0} -%}


{% for rsp in sub_instances_responses -%}
    {% set status = (rsp['value'] | json).status -%}
    {% set counts = counts.update({status|string: counts[status|string] + 1}) or counts -%}
{% endfor -%}

{
    "count201": {{ counts["201"] }},
    "count207": {{ counts["207"] }},
    "count400": {{ counts["400"] }}
}

Note: The expression{%set counts=counts.update(...) or counts%} is updating a dictionary (counts) with a new value and then reassigning the updated dictionary back to counts. It uses the or operator to ensure the value of counts is preserved: since counts.update({...}) returns None, the or operator ensures the variable counts retains its current state after the operation even if the update method does not return a usable value (because update returns None in Python).

Best Practices for Using Namespace

  • Use Namespace for Mutable Variables:
    • Only use namespace when you need mutable variables, such as counters or accumulators.
  • Keep Logic Simple:
    • Avoid overly complex nested logic inside loops that modify namespaces.
  • Debug with Readable Outputs:
    • Use pp_dict or tojson to inspect namespace objects during template development.
  • Prefer Dictionaries for Aggregations:
    • When managing multiple counters or accumulations, consider using a dictionary as an alternative to multiple namespace objects.

Exercise

Use the input context above in the template playground and the various templates described in this section.

Conclusion

Namespaces are a powerful tool for handling mutable variables in Jinja, but they are not always necessary. By understanding their use cases and alternatives, you can choose the most efficient approach for your workflow.