Multiple level template inheritance in Jinja2?

Viewed 45901

I do html/css by trade, and I have been working on and off django projects as a template designer. I'm currently working on a site that uses Jinja2, which I have been using for about 2 weeks. I just found out through reading the documentation that Jinja2 doesn't support multiple level template inheritance, as in you can't do more than one

{% extends "foo" %}

per rendering. Now I'm pretty sure you can do this in Django, which is powerful because you can specify a base template, specify 3 or 4 templates based on that, and then build the meat of your pages using those base templates. Isn't the point of inheritance so you have more power to abstract so your only really messing with unique code?

In any case I have no idea what to do here. I don't know if there is some way I can do it that will work as well as it could with the Django templates. I'm not exactly an expert at either Django or Jinja(2) but I can provide any information needed.

8 Answers

The way the documentation worded it, it seemed like it didn't support inheritance (n) levels deep.

Unlike Python Jinja does not support multiple inheritance. So you can only have one extends tag called per rendering.

I didn't know it was just a rule saying 1 extends per template.... I now know, with some help from the jinja irc channel.

After struggling for a long time, I found {{super}} for multiple levels of inheritance in jinja2 templates.

The following is inspired from https://stackoverflow.com/a/31093830/1300775.

base.html

<html>
<body>
  {% block title %}
    Brand
  {% endblock %}
</body>

layer-1.html

  {% extends "base.html" %}
  {% block title %}
    {{ super() }} - Section
  {% endblock %}

layer-2.html

  {% extends "layer-1.html" %}
  {% block title %}
    {{ super() }} - Article
  {% endblock %}

Rendering template layer-2.html will output Brand - Section - Article in block title.

Multiple inheritance and multiple-level inheritance are not the same. I understand the question is related to the latter.

Let me show my workaround for the problem:

parent-template.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset='utf-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Your Title</title>
    <link rel='stylesheet' href="{{ url_for('static', filename='css/main.css') }}">
    {% block head %}{% endblock %}
</head>

<body>
    {% block nav %}{% endblock %}
    {% block body %}{% endblock %}
</body>

</html>

child-template.html

{% extends 'parent-template.html' %}

{% block nav %}
<header>
    <div>
        <nav>
            ...
            [navbar html code]
            ...
        </nav>
    </div>
</header>
{% endblock %}

login.html (where I don't need navbar)

{% extends 'parent-template.html' %}

{% block body %}
<header>
    ...
    [header html code]
    ...
</header>
<main>
    ...
    [main html code]
    ...
</main>
{% endblock %}

home.html (where I need navbar)

{% extends 'child-template.html' %}

{% block body %}
<main>
    ...
    [main html code]
    ...
</main>
{% endblock %}

Both login.html and home.html uses all the data from parent-template, but only home.html uses data from child-template (the navbar).

You could use the following way to combine different contents into a single layout.html for various layout designs:

{% if instance == 'type1' %}

{% elif instance == 'type2' %}

{% else %}

{% endif %}

...and call:

render_template('layout', instance='%s' % instance)

in python code.

Related