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 ascriptsblock.- Inheritance chains:
page.htmlextendssection.htmlextendsbase.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
forloop unless declaredscoped:{% 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 %}. extendsaccepts 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.