Zum Inhalt

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.

Homepage

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ß":

1) zu Fuß
anz = 2
preis = 12.4545
print( str(anz) + " Bücher kosten " + str(anz*preis) + " EUR"
Ausgabe:

2 Bücher kosten 24.909 EUR

Im zweiten Schritt kann eine format-Anweisung genutzt werden:

2) Template + Format
msg = "{} Bücher kosten {:.2f} EUR"
print( msg.format(anz, anz*preis))
Ausgabe:

2 Bücher kosten 24.91 EUR

Im dritten Schritt kann die Formatierung weit übersichlicher mit Hilfe der f-String-Notation erzeugt werden:

3) f-String (Template)
msg = f'{anz} Bücher kosten {(anz*preis):.2f} EUR'
print(msg)
Ausgabe:

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.

Download ipynb

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).

main_1.py
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()
Download main_1.py

seite.html.jinja
<!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>
Download seite.html.jinja

gerenderte Ausgabe-html-Datei
<!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:

base.html.jinja
<!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 %}
        &copy; 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

chield.html.jinja
{% 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-Definition
{% macro input(name, value='', type='text', size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{
        value|e }}" size="{{ size }}">
{%- endmacro %}
macro-Verwendung
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>