Jinja Templates in Flask
Jinja template engine
Related Articles
Jinja
Jinja is a web template engine for python. Jinja lets variables, statements in html file and can split files not to repeat html code. Jinja templates are just .html file that we will render from flask later. Flask render_template method will generate jinja templates into HTML file and return to client side.
Why Flask render Jinja templates instead of returning html text
When we return simple text with flask return statement, we need to escape user input value to protect injection attacks.
Below code will show input name from url without escaping
@app.route("/<name>")
def home(name):
return f"Hello, {name}"
Without escape code will work when user gave string or number or some datatype. But you pass some script like this as input
http://127.0.0.1:5000/<a href=”javascript:alert(‘unsafe’);”>click here
click here</a>your home route will show Hello click here because script work in browser. then you click you will see javascript alert with unsafe text.
So we need to escape those script to string. escape() from markupsafe python module escape those script into string. You can test the code below and go to this route again
http://127.0.0.1:5000/<a href=”javascript:alert(‘unsafe’);”>click here
from markupsafe import escape@app.route("/<name>")
def home(name):
return f"Hello, {escape(name)}"
escape function escape html a tag into string. input javascript doesn’t work on browser. Jinja templates automatically escape and we can use Jinja templates with flask render_template().
documentation
how to use?
Install Jinja2
pip install Jinja2
A Jinja template doesn’t need to have a specific extension: .html
, .xml
, or any other extension is just fine. documentation
Limiters
you can use variables, statements and comments.
Variable
{{ }}
Statement
{% %}
Comment
{# #}
Create main.py and templates and test below code
Variable pass to Jinja
<h2>{{ name }}</h2>
<h2>{{ email }}</h2>
main.py
from flask import Flask, render_template
app = Flask(__name__)
# creating route
@app.route("/")
def home():
return render_template("home.html", name='Sophia', email="sophia@gmail.com")
if __name__ == "__main__":
app.run(debug=True)
home.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>{{ name }}</h2>
<h2>{{ email }}</h2>
</body>
</html>
Output
For loop in Jinja
Example
<ul>
{% for color in colors %}
<li> {{color}} </li>
{% endfor %}
</ul>
Change html and main.py as above
If statement in Jinja
Example
{% if name == 'James' %}
<h1> {{name}} </h1>
{% endif %}
Change html and main.py as above
if else statement
Example
{% if name == 'James' %}
<h1>{{ name }}</h1>
{% else %}
<h1>not James</h1>
{% endif %}
Change html and main.py as above
Template Inheritance
block tag
{% block head %}{% endblock %}
super tag
{{ super() }}
Base Template
create base.html in templates
base.html
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2008 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
Child Template
home.html
{% extends "base.html" %}{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>{{self.title()}}</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}
- extends base template
- create block tag from base.html and extends html css code
- super tag in head block will give the result from parent template(base.html)
Connect with Bootstrap
connect with bootstrap is easy. link the bootstrap cdn in base.html as follow
base.html
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<title>{% block title %}{% endblock %}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
{% endblock %}</head><body>
{% block content %}
<h1>helo</h1>
{% endblock %}<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js" integrity="sha384-eMNCOe7tC1doHpGoWe/6oMVemdAVTMs2xqW4mwXrXsW0L84Iytr2wi5v2QjrP/xp" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.min.js" integrity="sha384-cn7l7gDp0eyniUwwAZgrzD06kc/tftFf19TOAs2zVinnD/C7E91j9yyk5//jjpt/" crossorigin="anonymous">
</script>
</body></html>
home.html
{% extends "base.html" %}{% block title %}
My Website
{% endblock %}{% block content %}
<div class="alert alert-primary" role="alert">
A simple primary alert—check it out!
</div>
<div class="alert alert-secondary" role="alert">
A simple secondary alert—check it out!
</div>
{{ super() }}
{% endblock %}
Url For
example
<a href="{{url_for('add')}}">go to add page</a>
main.py
from flask import Flask, render_template
app = Flask(__name__)
# creating route
@app.route("/")
def home():
return render_template("home.html", name="Jo")
@app.route("/add")
def add():
return render_template("add.html")
if __name__ == "__main__":
app.run(debug=True)
home.html
<body>
<a href="{{url_for('add')}}">go to add page</a>
</body>
Flash messages
Flash messages use to show error messages in jinja templates. Especially in login and register to show user error messages (eg, incorrent password, lastname required)
flash("incorrect password")
main.py
from flask import Flask, render_template, flash, request@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
user = User.query.filter_by(email=request.form['email']).first()
if user:
if check_password_hash(user.password, request.form['password']):
login_user(user)
return redirect(url_for("secrets"))
else:
flash("incorrect password")
else:
flash("not found email")
return render_template("login.html")
login.html
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}