Python Template Engines — Jinja2 & String Templates
Templating generates dynamic text from templates with variable substitution and logic. Essential for HTML generation, email templates, and configuration files.
Learning Objectives
- Use Python's string.Template for simple substitution
- Master Jinja2 for complex templating
- Apply template inheritance for reusable layouts
- Generate HTML and documents from templates
string.Template (Standard Library)
from string import Template
# Simple substitution
template = Template("Hello, $name! Your balance is $${amount}.")
result = template.substitute(name="Alice", amount=1000)
print(result) # Hello, Alice! Your balance is $1000.
# Safe substitution (no error on missing keys)
result = template.safe_substitute(name="Bob")
print(result) # Hello, Bob! Your balance is $${amount}.
Jinja2 Basics
from jinja2 import Template
# Simple variable substitution
template = Template("Hello, {{ name }}!")
print(template.render(name="Alice"))
# Filters
template = Template("{{ name | upper }}")
print(template.render(name="alice")) # ALICE
# Control flow
template = Template("""
{% for item in items %}
- {{ item }}
{% endfor %}
""")
print(template.render(items=["Apple", "Banana", "Cherry"]))
# Conditions
template = Template("""
{% if score >= 90 %}
Grade: A
{% elif score >= 80 %}
Grade: B
{% else %}
Grade: C
{% endif %}
""")
Template Inheritance
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
# base.html — the parent template
"""
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
<nav>{% block nav %}{% endblock %}</nav>
<main>{% block content %}{% endblock %}</main>
<footer>{% block footer %}Default Footer{% endblock %}</footer>
</body>
</html>
"""
# page.html — extends base
"""
{% extends "base.html" %}
{% block title %}{{ page_title }}{% endblock %}
{% block nav %}
<a href="/">Home</a>
<a href="/about">About</a>
{% endblock %}
{% block content %}
<h1>{{ heading }}</h1>
<p>{{ body }}</p>
{% endblock %}
"""
Generating HTML Reports
from jinja2 import Template
report_template = Template("""
<html>
<head><title>Sales Report</title></head>
<body>
<h1>Sales Report — {{ period }}</h1>
<table border="1">
<tr><th>Product</th><th>Units</th><th>Revenue</th></tr>
{% for product in products %}
<tr>
<td>{{ product.name }}</td>
<td>{{ product.units }}</td>
<td>${{ "%.2f" | format(product.revenue) }}</td>
</tr>
{% endfor %}
</table>
<p><strong>Total Revenue:</strong> ${{ "%.2f" | format(total_revenue) }}</p>
</body>
</html>
""")
html = report_template.render(
period="January 2024",
products=[
{"name": "Widget A", "units": 150, "revenue": 4500.00},
{"name": "Widget B", "units": 80, "revenue": 3200.00},
],
total_revenue=7700.00
)
Key Takeaways
- Use
string.Templatefor simple substitution (no dependencies) - Use Jinja2 for complex HTML/document generation
- Template inheritance reduces duplication
- Auto-escaping prevents XSS in HTML
- Use
|safeto disable escaping for trusted HTML - Filters transform variables in templates
- Macros are reusable template components