Template inheritance

Jinja · Practical · 12 min

Inheritance gives every page the same layout without copy-pasting headers and footers.

Template inheritance is Jinja's most powerful layout tool. A base template defines the page skeleton and marks replaceable regions with blocks:

<title>{% block title %}My site{% endblock %}</title>
<main>{% block content %}{% endblock %}</main>

A child template starts with {% extends "base.html" %} and overrides only the blocks it needs. Anything in a child outside blocks is ignored, because the base decides the output.

Useful details:

  • {{ super() }} renders the parent's version of the block, so a child can append rather than replace, for example adding a script to a scripts block.
  • Inheritance chains: page.html extends section.html extends base.html; each level can override blocks.
  • {% block sidebar required %}{% endblock %} forces every rendering child to override it.
  • Blocks can't see variables defined in an outer for loop unless declared scoped: {% block row scoped %}.
  • Reuse a block's content elsewhere with {{ self.title() }}, for example the title in both <title> and <h1>.
  • Name the end tag for readability: {% endblock content %}.
  • extends accepts a variable, so the layout can be chosen at runtime: {% extends layout or "base.html" %}.

A block can only be defined once per template, and extends should be the first tag. Keep base templates small and stable; pages change, the skeleton rarely does.

Example

from jinja2 import DictLoader, Environment

env = Environment(loader=DictLoader({
    "base.html": "<title>{% block title %}Site{% endblock %}</title>\n"
                 "<h1>{{ self.title() }}</h1>\n"
                 "<main>{% block content %}{% endblock %}</main>\n"
                 "<script src=app.js></script>{% block scripts %}{% endblock %}",
    "post.html": "{% extends 'base.html' %}"
                 "{% block title %}{{ post.title }} - {{ super() }}{% endblock %}"
                 "{% block content %}{{ post.body }}{% endblock %}"
                 "{% block scripts %}<script src=post.js></script>{% endblock %}"
                 "This text is outside any block and never rendered.",
}), autoescape=True)

print(env.get_template("post.html").render(post={"title": "Hello", "body": "First post"}))
# <title>Hello - Site</title>
# <h1>Hello - Site</h1>
# <main>First post</main>
# <script src=app.js></script><script src=post.js></script>

Remember

  • Base template defines blocks; children extend it and override blocks
  • super() includes the parent's block content
  • self.blockname() reuses a block; required forces overrides

Watch out for

  • Putting content outside blocks in a child template and wondering why it never appears.

Check yourself

  1. In a child template, what does {{ super() }} inside a block do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: jinja.palletsprojects.com/en/stable/templates/#template-inheritance