Flask Rendering Templates
Flask is a lightweight Python web framework that enables developers to build web applications easily. One of its key features is template rendering, which allows dynamic content generation using Jinja2 templating. In this guide, we'll explore how to render templates in Flask.
Setting up Flask
Setting up a new flask app requires creating and activating a virtual environment and installing flask to it.
Creating virtual environment
Use the command below to create a new virtual environment in recent Python versions.
python -m venv venv
Activate the virtual environment
For Windows:
venv\Scripts\activate
For Linux/macOS: source
venv/bin/activate
Install Flask
pip install flask
This will install Flask in the virtual environment created specifically for our project.
Creating a Flask Application
Create a new file app.py and add the following code to create a basic flask app:
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run()
Explanation:
- Flask(__name__): Initializes the Flask app.
- app.run(): Starts the server.
Rendering HTML Templates
One of Flask's powerful features is its ability to render HTML templates using Jinja2. Instead of returning plain strings in routes, we can use render_template() to serve HTML files dynamically.
Create a templates Folder
Flask looks for HTML files in a special directory called templates. Create a folder named templates in your project directory and create the index.html file.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Flask App</title>
</head>
<body>
<h2>Welcome to Flask</h2>
<p>This is a basic template rendering example.</p>
</body>
</html>
Modify app.py to Render the Template
Updating app.py to use render_template():
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
if __name__ == "__main__":
app.run()
Explanation:
- @app.route("/"): Maps the root URL (/) to the index() function.
- render_template("index.html"): Renders the HTML file.
Templating With Jinja2 in Flask
Now, we'll create a new route for demonstrating the usage of the Jinja template and add it in app.py.
@app.route("/<name>")
def welcome(name):
return render_template("welcome.html", name=name)
We create a route "/<name>" linked to the welcome function. The <name> part captures any value after / and passes it as a parameter to render_template(). This makes the variable accessible in the template for rendering or modification.
Create a welcome.html file inside the templates folder with the following markup.
<!DOCTYPE html>
<html>
<head>
<title>FlaskTest</title>
</head>
<body>
<h2>Welcome To GFG</h2>
<h3>Welcome, {{name}}</h3>
</body>
</html>

Flask - Jinja Template Inheritance
Instead of reusing full templates, we can inherit them using Jinja blocks. Here's how:
- Create a block in a template using {% block <name> %} ... {% endblock %}.
- This allows other templates to extend it and replace the block content.
- In index.html, define a block using {% block body %} ... {% endblock %}.
- Everything above {% block body %} stays the same in all templates, while content inside the block can change.
- The block ends with {% endblock %}, allowing templates to override only specific sections.
templates/index.html
<!DOCTYPE html>
<html>
<head>
<title>FlaskTest</title>
</head>
<body>
<h2>Welcome To GFG</h2>
<h4>Flask: Rendering Templates</h4>
<a href="{{ url_for('home') }}">Home</a>
<a href="{{ url_for('index') }}">Index</a>
{% block body %}
<p>This is a Flask application.</p>
{% endblock %}
</body>
</html>
We exclude <p> tags because everything above {% block body %} and below {% endblock %} is copied. We use absolute URLs with {{ url_for() }}, which dynamically generates URLs by passing the function name as a string.
Create home.html to reuse the body block with the following content.
templates/home.html
{% extends 'index.html' %}
{% block body %}
<p> This is a home page</p>
{% endblock %}
This extends, not includes, index.html using {% extends 'file.html' %}, ensuring the block is correctly placed. Unlike {% include %}, which simply inserts content, extending properly nests the body text.
Let's add a route for home.html in app.py.
@app.route("/home")
def home():
return render_template("home.html")
This is a route bound to the "/home" URL with the home function that renders the template "home.html" that we created just right now.

The URL is dynamically generated, avoiding the need to hardcode template paths. The block correctly inherits from the base template. To verify, check the page source in your browser.
<!DOCTYPE html>
<html>
<head>
<title>FlaskTest</title>
</head>
<body>
<h2>Welcome To GFG</h2>
<h4>Flask: Rendering Templates</h4>
<a href="/home">Home</a>
<a href="/">Index</a>
<a href="/about">About</a>
<a href="/documentation">Documentation</a>
<p> This is a home page</p>
<p>must use extends not include</p>
</body>
</html>
Inducing Logic in Templates
Templates support for loops and if conditions, making them powerful for dynamic content. We can easily render lists from Python in an HTML template.
Using for loops in templates
We'll create a route /about that binds to the about function, rendering about.html. Before returning the template, we'll pass a list of dummy strings to render_template().
@app.route("/about")
def about():
sites = ['twitter', 'facebook', 'instagram', 'whatsapp']
return render_template("about.html", sites=sites)
We've created the /about route, bound to the about function. Inside it, we define a list Sites with dummy strings and pass it to render_template() as sites. You can name it anything, but use the same name in the template.
Let's create about.html with the following content.
templates/about.html
{% extends 'index.html' %}
{% block body %}
<ul>
{% for social in sites %}
<li>{{ social }}</li>
{% endfor %}
</ul>
{% endblock %}
We can use for loops in templates inside {% %}, just like in Python. The sites list, passed from the route function, is accessed using {{ }}. Variables use {{ }}, while loops and logic blocks use {% %}.
To make navigation easier, add its URL to index.html like this:
<!DOCTYPE html>
<html>
<head>
<title>FlaskTest</title>
</head>
<body>
<h2>Welcome To GFG</h2>
<h4>Flask: Rendering Templates</h4>
<a href="{{ url_for('home') }}">Home</a>
<a href="{{ url_for('index') }}">Index</a>
<a href="{{ url_for('about') }}">About</a>
{% block body %}
<p>This is a Flask application.</p>
{% endblock %}
</body>
</html>
This is not mandatory but it creates an accessible link for ease.

The template dynamically generates the list, which is useful for fetching data from a database in a production app. It also helps automate repetitive tasks that would be tedious to do manually.
If statement in HTML Template in Python Flask
Flask templates also support if-else conditions, allowing for dynamic content. Just like loops, they help create flexible templates.
For example, let’s define a contact route:
- The URL "contact/<role>" is bound to the contact function.
- It renders contacts.html, passing role as an argument.
- We can assign role to another variable, like person, in the template for better readability.
@app.route("/contact/<role>")
def contact(role):
return render_template("contact.html", person=role)
This creates the route as desired and parses the variable role as a person to the template. Now let us create the template.
template/contact.html
{% extends 'index.html' %}
{% block body %}
{% if person == "admin" %}
<p> Admin Section </p>
{% elif person == "maintainer" %}
<p> App Source Page for Maintainer</p>
{% elif person == "member" %}
<p> Hope you are enjoying our services</p>
{% else %
<p> Hello, {{ person }}</p>
{% endif %}
{% endblock %}
In the template, we check the person variable, which comes from the URL and is passed via render_template(). The if-else syntax is similar to Python but enclosed in {% %}. It follows a simple if-elif-else structure to generate HTML based on the value.

The template dynamically renders content based on the role variable in the URL. However, you can't create a direct link for this since the role must be entered manually.