In this tutorial, we are going to see one of the distinctive features of jinja templates called jinja template inheritance.
Jinja template inheritance:
The idea of template inheritance is that we are going to design a base template that contains all the common features that belong to all the pages, and then we are going to provide the content specific to each page in a derived template.
Versions:
- Python 3.8.5
- Flask 2.0.1
Jinja template inheritance Example:
As part of this example, I am going to implement a header bar, obviously, we want this header bar to appear on all the pages of our application.
Application Structure:
(venv) flask-jinja-inheritance %
.
├── app
│ ├── __init__.py
│ ├── routes.py
│ └── templates
│ ├── header.html
│ ├── index.html
│ └── profile.html
└── jinja-templates.py
Creating generic header page
Here I would like to implement the header page in a way that can integrate every template that I want. Usually, the header should be present on all the pages in the application.
header.html
<html>
<head>
<title>My Blog</title>
</head>
<body>
<h2 style="color:#093657">My Blog</h2> <a href="/">Home</a> | <a href="/profile">Profile</a>
<hr>
{% block content %} {% endblock %}
</body>
</html>
On the above, I created a simple header portion with the blog name, containing home and profile page links init, underneath that, created a new jinja construct called {% block content %}
to specify the location where all the derived templates need to insert their page-specific content.
Now I have a pretty generic header page, that I can use all for my pages, now I need to prepare index and profile templates by extending this.
Preparing index.html with a simple welcome message.
{% extends "header.html" %}
{% block content %}
<h1 style="color:#093657"> Welcome
{% if user %}
{{user.name}}
{% else %}
Buddy!
{% endif %}
</h1>
{% endblock %}
The way I am linking this index template with the header template is through the extends construct {% extends "header.html"%}
and then I provided the content that specific to this page in block content {% block content %}
is the same name which we specified in the header template.
Now let’s prepare the profile page with some more information about the user.
profile.html
{% extends "header.html" %}
{% block content %}
Hobbies:
<div>
<p><ul>
{% for hobby in profile.hobbies %}
<li>{{hobby}}</li>
{% endfor %}
</ul></p>
</div>
Interested Books:
<div>
<p><ul>
{% for key in profile.interested_books %}
{{key}}
<ul>
{% for book in profile.interested_books.get(key)%}
<li>{{book}}</li>
{% endfor %}
</ul>
{% endfor %}
</ul></p>
</div>
{% endblock %}
Create routes.py
from app import app
from flask import render_template
@app.route('/')
def index():
user_info = {
'name':'Chandra'
}
return render_template('index.html', user=user_info)
@app.route('/profile')
def profile():
user = {
'name': 'Chandra'
}
profile = {
'hobbies':['Blogging','Reading Books','Playing chess'],
'interested_books':{
'Java':['Thinking in Java','Inside the Java virtual machine'],
'Python':['Fluent Python']
}
}
return render_template('profile.html', user=user, profile=profile)
On the above routes.py
I have two routes representing index.html
and profile.html
When I pass the index.html
or profile.html
to the render_template()
function it’s going to find that there is a reference to a base template (header template) so that it’s going render the header template in the place where the empty block content {% block content %} {% endblock %}
and it’s going to put the contents that we have in the profile/index pages.
Now let’s try run this:
There you can see our header section and home page content. Now try access Profile page
References:
Happy Learning 🙂