Search code examples
pythonhtmljinja2

Using the same template recursively in Jinja2


Suppose I have a tree-like data structure in Python:

class Node:
    def __init__(self, name: str, neighbors: Optional[Iterable[Node]] = None) -> None:
        self.name = name
        self.neghbors = neighbors or []


grand_child1 = Node("grand_child1")
grand_child2 = Node("grand_child1")

child = Node("child", [grand_child1, grand_child2])

root = Node("root", [child])

Now I want to render this structure into a ul in HTML. I want the output to be something like this:

<ul>
    <li>root</li>
    <ul>
        <li>child</li>
        <ul>
            <li>grand_child1</li>
            <li>grand_child2</li>
        </ul>
    <ul>
</ul>

To do this I want to use a Jinja template. The what I want to extract from each node is the same, it's just that I want to capture the tree structure and avoid duplicate code. Is there a way to use a template recursively? Something like this:

<ul>
{% for root in roots %}
    <li>{{ root.name }}</li>
    {# this template applied for the neighbors #}
{% endfor %}
</ul>

Solution

  • Turns out you can define macros in jinja which work like functions. Something like this will do the trick:

    {% macro make_ul(roots) -%}
    <ul>
        {% for root in roots %}
        <li>{{ root.name }}</li>
        {{ make_ul(root.neighbors) }}
        {% endfor %}
    </ul>
    {%- endmacro %}
    
    {{ make_ul(roots) }}
    

    This way the macro will call itself recursively till it hits the leaves of the tree.