Jinja2 -Template-Engine
Jinja2 ist ein sehr weit verbreiteter Template-Renderer für eine Vielzahl von Anwendungen, in denen ASCII-Files an dynamische Inhalte angepasst werden müssen. Er setzt Python voraus.
Installation
pip install Jinja2
Einführung
Zum Grundverständnis mag folgende kleines py-Beispiel genügen. Hierun soll eine print-Ausgabe erzeugt werden, die aus einem String besteht, in dem verschiedene Variablen-Inhalten hinein-gerendert werden sollen. In Python existiert für solche Aufgaben der Format-String.
Im ersten Schritt lösen wir es "zu Fuß":
anz = 2
preis = 12.4545
print( str(anz) + " Bücher kosten " + str(anz*preis) + " EUR"
2 Bücher kosten 24.909 EUR
Im zweiten Schritt kann eine format
-Anweisung genutzt werden:
msg = "{} Bücher kosten {:.2f} EUR"
print( msg.format(anz, anz*preis))
2 Bücher kosten 24.91 EUR
Im dritten Schritt kann die Formatierung weit übersichlicher mit Hilfe der f-String-Notation erzeugt werden:
msg = f'{anz} Bücher kosten {(anz*preis):.2f} EUR'
print(msg)
2 Bücher kosten 24.91 EUR
Note
Das Konzept des Template und den Platzhaltern {..}
greift die Jinja2-Engine auf und erweitert sie um Ablauf- und Logik-Elemente.
Programm-Rahmen
Um mit der Jinja2-Template arbeiten zu können müssen einige Schritte in einem Python-Skript vorbereitet sein. Hier soll ein allgemeingültiges einfaches Beispiel entwickelt werden.
Rendern einer html-Datei
Neben dem eigentlichen Template seite.html.jinja
braucht es natürlich auch das Python-Skript main_1.py
. Als Ergebnis schreibt das Skript die Datei seite.html
, die später von einem Webserver ausgeliefert werden kann (siehe Kap. Flask).
from jinja2 import Template
TEMPLATE_FILE = "./seite.html.jinja"
OUT_FILE = "./seite.html"
# Daten definieren
data = {"name": "Franz", "age": 18.3}
nav = [{"href": "www.google.com", "caption": "google"},
{"href": "www.bing.com", "caption": "bing"}
]
def main():
# Template-Datei öffnen
with open(TEMPLATE_FILE, 'r') as template_file:
template = Template(template_file.read())
# Rendern mit den Daten (wo immer sie herkommen ;-)
output = template.render(data=data, nav=nav)
print(output) # Testausgabe
with open(OUT_FILE, "w") as w_file:
w_file.write(output)
if __name__ == '__main__':
main()
main_1.py
<!DOCTYPE html>
<html lang="de">
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="nav">
{% for item in nav -%}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor -%}
</ul>
<h1>My Webpage</h1>
Hallo {{ data.name }}, Du bist {{ data.age }} Jahre alt!
{# a comment #}
</body>
</html>
seite.html.jinja
<!DOCTYPE html>
<html lang="de">
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="nav">
<li><a href="www.google.com">google</a></li>
<li><a href="www.bing.com">bing</a></li>
</ul>
<h1>My Webpage</h1>
Hallo Franz, Du bist 18.3 Jahre alt!
</body>
</html>
Syntax
Hier gibt es die ausführliche Template Designer Documentation
Begrenzer
{% ... %}
für Statments (Kontrollstrukturen){{ ... }}
für Ausdrücke{# ... #}
für Kommentare
Variablen
Template Variablen werden als Dictionary dict()={"key":"value"}
an den Template-Renderer übergeben. Es kann die Punkt-Notation .
als auch die Key-Notation []
genutzt werden:
{{ foo.bar }}
{{ foo['bar'] }}`
Kommentar
Kommentarblöcke werden mit dem Klammerpaar {# ... #}
gekennzeichnet:
{# Test-Sequenz:
{% for user in users %}
...
{% endfor %}
#}
Template Vererbung
Templates können beliebig als Blöcke verschachtelt werden. Hieraus enstehen mächtige Mechanismen für Webseiten-Layouts.
(Das folgende Beispiel entstammt der Jinja2-Webseite)
Base-Template
Das Template base.html.jinja
soll das "Basis"-Gerüst einer komplexeren Webseite darstellen:
<!DOCTYPE html>
<html lang="de">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - Meine Webseite</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2025 by <a href="http://domain.invalid/">foo</a>.
{% endblock %}
</div>
</body>
</html>
In diesem Beispiel definieren die {% block %}
Tags vier Blöcke, die durch Templates ("Child-Templates") gefüllt werden können.
Chield Template
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color:rgb(6, 63, 11); }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}
Das {% extends %}
Tag steuert die Erweiterung durch ein weiteres Template.
Wird der FileSystemLoader
eingesetzt, dann kann basierend auf den Dateinamen eingebunden werden:
{% extends "layout/default.html.jinja" %}
Super Blocks
Super-Blöcke rendern den Parent-Block in das Chield-Template:
{% block sidebar %}
<h3>Inhaltsverzeichnis</h3>
...
{{ super() }}
{% endblock %}
Liste der Kontrollstrukturen
For
- iteriert über alle Elemente eine Liste (von
dict()
):
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
Es kann auch auf die key : value
getrennt zugegriffen werden:
<dl>
{% for key, value in my_dict.items() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
</dl>
If
das Jinja-If entspricht dem Python-If:
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
Macros
Eine starke Erweiterung stellen Macros dar. Wiederkehrende und parametrierbare Aufgaben lassen sich hierin abbilden. Sie können auch "includes
" (Macro-Bibliotheken) werden:
{% macro input(name, value='', type='text', size=20) -%}
<input type="{{ type }}" name="{{ name }}" value="{{
value|e }}" size="{{ size }}">
{%- endmacro %}
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>