Skip to content

Flask - Templates

While you can return HTML directly as strings from your Flask view functions, this quickly becomes unmanageable and mixes presentation logic with application logic. Flask integrates the powerful Jinja2 templating engine to solve this problem.

Instead of building HTML strings in Python:

Section titled “Instead of building HTML strings in Python:”
# Less maintainable approach
@app.route('/old')
def old_hello():
user = 'Alice'
# Embedding HTML directly in Python code
return f'<html><body><h1>Hello {user}!</h1></body></html>'
  1. Create HTML files (templates) with special placeholders for dynamic content.

  2. Use Flask’s render_template() function in your view function to render these templates, passing in any necessary data.

To render a template, you import render_template from Flask and call it within your view function, providing the template filename and any variables you want to pass to the template as keyword arguments.

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/hello/<name>')
def hello(name):
# Renders 'templates/user_greeting.html'
# Passes the 'name' variable from the URL to the template
# under the variable name 'username'.
return render_template('user_greeting.html', username=name)
if __name__ == '__main__':
app.run(debug=True)

By default, Flask looks for templates in a subfolder named templates located in the same directory as your main application script or package.

/your_project
app.py
/templates
user_greeting.html
layout.html
# ... other templates

Jinja2 templates are primarily HTML files containing special delimiters to embed logic and variables:

  • {{ ... }} for Expressions: Used to print the value of a variable or the result of an expression to the template output. Jinja2 automatically handles HTML escaping for security.
  • {% ... %} for Statements: Used for control structures like loops (for), conditionals (if/elif/else), template inheritance (extends, block), and macros.
  • {# ... #} for Comments: Used for comments that are ignored by the template engine and won’t appear in the final HTML output.

Example Template (templates/user_greeting.html):

Section titled “Example Template (templates/user_greeting.html):”
<!DOCTYPE html>
<html>
<head>
<title>Greeting</title>
</head>
<body>
{# This is a comment, it won't be rendered #}
{# Print the 'username' variable passed from Flask #}
<h1>Hello, {{ username }}!</h1>
<p>Welcome to our application.</p>
</body>
</html>

Running the example above and navigating to /hello/Bob would render this HTML, replacing {{ username }} with Bob.

You can use Python-like control structures within {% ... %} blocks.

@app.route('/grade/<int:score>')
def show_grade(score):
return render_template('grade_result.html', marks=score)
<!DOCTYPE html>
<html>
<body>
<h1>Exam Result</h1>
{% if marks >= 90 %}
<p>Grade: A</p>
{% elif marks >= 75 %}
<p>Grade: B</p>
{% elif marks >= 60 %}
<p>Grade: C</p>
{% else %}
<p>Grade: F - Please see instructor.</p>
{% endif %}
</body>
</html>
@app.route('/items')
def show_items():
item_list = ['Apple', 'Banana', 'Cherry']
return render_template('item_list.html', items=item_list)
<!DOCTYPE html>
<html>
<body>
<h1>Available Items</h1>
{% if items %}
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% else %}
<p>No items available.</p>
{% endif %}
</body>
</html>

Jinja2’s most powerful feature is template inheritance. It allows you to define a base layout template (e.g., layout.html) with common elements (header, footer, navigation) and define specific blocks that child templates can override.

<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Application{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<header>
<h1>My Website</h1>
</header>
<main>
{% block content %}
{# Child templates will put their content here #}
{% endblock %}
</main>
<footer>
<p>&copy; 2023 Me</p>
</footer>
</body>
</html>

Child Template (templates/user_greeting.html updated):

Section titled “Child Template (templates/user_greeting.html updated):”
{% extends 'layout.html' %}
{% block title %}Greeting for {{ username }}{% endblock %}
{% block content %}
<h2>Hello, {{ username }}!</h2>
<p>Welcome to our application.</p>
{% endblock %}

When user_greeting.html is rendered, Jinja2 will:

  1. Load layout.html.
  2. Replace the {% block title %} in layout.html with the content of the {% block title %} from user_greeting.html.
  3. Replace the {% block content %} in layout.html with the content of the {% block content %} from user_greeting.html.

This promotes code reuse and makes maintaining a consistent look and feel across your application much easier.