Bei der Entwicklung von Webseiten kommt es häufig vor, dass man größere Mengen Text ausgeben will, in der Regel ist das meist HTML oder XML. Man kann zwar jeglichen Text mit Stringverkettungen zusammensetzen, jedoch ist diese Art und Weise recht umständlich und führt dazu, dass das eigentliche Python-Programm unübersichtlich wird. Daher wurden sogenannte Template-Engines entwickelt die Vorlagen (Templates) nach einem bestimmten Vorgehen mit Inhalt füllen.
Die einfachsten "Template-Systeme" bringt Python bereits mit: Die String Formatting Operations und die geringfügig komplexeren Template-Strings. Diese Funktionieren tatsächlich wie Vorlagen mit Leerstellen, die später einfach nur mit Werten befüllt werden. Weitere Informationen dazu findest du weiter unten oder auf der Seite String-Formatter.
Inhalt
Hinweise zu den unten verwendeten Termen
- XML
- Wenn bei einer Template-Engine in der Spalte "XML" ein ja zu Lesen ist, heißt das, dass sie auf XML aufbaut und dementsprechend valides XML als Eingabeformat benötigt.
- sandboxed
- Eine Template Engine ist "sandboxed", wenn es vom Template aus nicht möglich ist beliebigen Quellcode auszuführen. Dies kann zum Beispiel wichtig sein, wenn man Benutzern einer Blog-Hosting-Platform die Möglichkeit geben will ihr Blog im Design zu ändern ohne den Server durch Schadcode zu kompromittieren.
- i18n
- Ist in dieser Spalte ein "ja" zu Lesen, bietet die Template-Engine Unterstützung für sprachabhängige Inhalten wie Übersetzungen.
- Fragmente
- Manche Template Engines bieten die Möglichkeit an fragmentarische Templates gesondert zu rendern (beispielsweise ohne DOCTYPE).
- Template Inheritance
- Erlaubt es das Layout in eine andere Datei auszulagern und Inhalte in Platzhalter einzufügen. Dies ist grob vergleichbar mit Template-Vererbung.
- Debugging Support
- Wenn in dieser Spalte ein ja zu Lesen ist, stellt die Template-Engine genügend Informationen bereit um Templates debuggen zu können. Bei einem Syntax Error kann man dann z.B. die richtige Zeile ablesen etc. Dies ist sehr wichtig, denn manchmal ist es schwer Fehler in den Templates zu finden.
- Filter / Helpers
- bestimmte Template-Engines stellen Hilfsfunktionen bereit, die man in Templates häufig brauchen kann. Zum Beispiel eine Funktion um Texte nach 80 Zeichen zu brechen, XML-Attribute automatisch zu erstellen etc.
Mit Bordmitteln
Die erste vorgeschlagene Template-Engine ist eine Engine die textbasiert ist und somit für alle Arten von Ausgabeformaten geeignet ist. Ihr größter Vorteil ist es, dass sie bereits in die Sprache eingebaut ist und somit keinerlei zusätzliche Abhängigkeiten hat! Es geht um die in Python seit jeher vorhandenen Template-Strings die wohl die einfachste Art sind Templates überhaupt zu nutzen. Diese Einfachheit kommt zum Preis der fehlenden Flexibilität: sie funktionieren wirklich nur wie Text mit Platzhaltern. Schleifen, Bedingungen oder ähnliches fehlt komplett.
1 output = 'Du bist %(years)s Jahre alt und das Zehnfache deines Alters ist %(years_ten)s.'
2 print output % {'years': 10, 'years_ten': 100}
In Python 2.4 wurde zusätzlich noch die Klasse string.Template eingeführt, welche eine weitere sehr simple Template-Engine zur Hand hat. Ihr Vorteil gegenüber den String-Formattern ist, dass die Templates etwas einfacher werden. Bei den String-Formattern kommt es öfters vor, dass man etwas vergisst, wie das abschliessende s bei %(years)s.
1 from string import Template
2
3 # Template erstellen
4 output = Template('Du bist $years Jahre alt und das Zehnfache deines Alters ist $years_ten.')
5 # Template befüllen und anzeigen
6 print output.substitute({'years': 10, 'years_ten': 100})
7 # geht auch so:
8 print output.substitute(years=10, years_ten=100)
Die Ausgabe ist in beiden malen:
Du bist 10 Jahre alt und das Zehnfache deines Alters ist 100.
Weitere Informationen dazu, siehe String-Formatter
Cheetah
Cheetah ist eine verbreitete, relativ mächtige Template-Engine, mit der man HTML, SGML, XML, SQL, Postscript, LaTeX und andere textbasierte Formate erstellen kann.
Cheetah benutzt bewusst eine nicht HTML-ähnliche Syntax. Das hat den Vorteil, die Cheetah-Tags aus dem HTML-Code herausstechen und dass Editoren mit Syntax-Highlighting das Ganze besser darstellen. (Sonst gibt es gerne mal Probleme bei Tags innerhalb anderer Tags.)
<html> <head><title>$title</title></head> <body> <table> #for $client in $clients <tr> <td>$client.surname, $client.firstname</td> <td><a href="mailto:$client.email">$client.email</a></td> </tr> #end for </table> </body> </html>
SimpleTAL
Eine recht schlanke Template-Engine. Es implementiert TAL, TALES und METAL aus dem mächtigen Framework Zope
Das Template-System benutzt eigene Tags und Attribute im XML-Namespace-Stil:
<html>
<body>
<h1 tal:content="title">
<h2 tal:condition="username">Welcome back <b tal:replace="username">Username here</b></h2>
<p>
Hot topics for today are:
<ul>
<li tal:repeat="news hotItems">
<a tal:attributes="href news/link" tal:content="news/title">News item</a>
</li>
</ul>
</p>
</body>
</html>
Kid / Genshi
|
Kid |
Genshi |
XML |
ja |
ja |
sandboxed |
nein |
nein |
i18n |
nein |
ja |
Fragmente |
ja |
nein |
Streaming |
nein |
ja* |
Template Inheritance |
ja |
ja |
Debugging Support |
nein |
ja |
Filter / Helpers |
nein |
ja |
X-Path |
nein |
ja |
Link |
*Der Stream kann momentan noch nicht zum Rendern verwendet werden.
Kid wurde als einfache XML Templating Sprache entwickelt und hatte sich sehr schnell als Standard-Template-Sprache für TurboGears durchgesetzt. Kid behandelt Templates wie Python-Module und erstellt .pyc-Dateien für diese. Unglücklicherweise ist die Implementierung stellenweise sehr unglücklich ausgefallen, so ist es nicht möglich bei Fehlermeldungen die korrekte Zeilennummer im Template zu bekommen.
Aus diesem Grund wurde Genshi als neue Template-Engine für Trac entwickelt. Sie basiert stark auf der Syntax von Kid, räumt aber sehr erfolgreich mit seinen Nachteilen auf. Weiterhin ist alternativ zur Generierung von gültigem XML auch die Erzeugung von Klartext implementiert worden, doch ist die Unterstützung für Text-Templates nur rudimentär und nur als Zsatzbonbon zu sehen.
Gegenüber Kid sind zudem einige weitere Template-Direktiven hinzugekommen und alternativ zur Attribut-Form (etwa <span py:if="True">...</span>) können auch Elemente (entsprechend <py:if test="True">...</py:if>) verwendet werden, was nicht selten die Lesbarkeit deutlich erhöht.
Weiters verwendet Genshi anstelle von py:layout und einigen Anwendungen von py:match XIncludes, um etwa (mit py:def oder py:match) vordefinierte Template-Teile in ein Template zu importieren oder ein Layout-Grundgerüst auf den Template-Inhalt anzuwenden. Dabei kann XPath verwendet werden um Elemente aus dem Stream auszuwählen.
Es zeichnet sich immer mehr eine Ablösung von Kid durch Genshi ab und es gibt keine Gründe mehr für Kid. Genshi ist schneller, hat mehr Features und das Projekt wird aktiv betreut.
page.html
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
lang="en">
<xi:include href="base.html" />
<head>
<title>Memberlist</title>
</head>
<body>
<ul>
<li py:for="user in users"><a href="${user.url}">${user.username}</a></li>
</ul>
</body>
</html>base.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="base.html" />
<head py:match="head">
<title>${select('title/text()')} | My Webpage</title>
</head>
<body py:match="body">
<div class="header">
<h1>My Webpage</h1>
</div>
<div class="body">
${select('*|text()')}
</div>
</body>
</html>
Django / Jinja
|
Django |
Jinja |
XML |
nein |
nein |
sandboxed |
ja |
ja |
i18n |
ja* |
ja |
Fragmente |
nein |
nein |
Streaming |
nein |
ja |
Template Inheritance |
ja |
ja |
Debugging Support |
ja* |
ja |
Filter / Helpers |
ja |
ja |
Link |
Hinweis mit "*" markierte Features sind für Django nur unter der Verwendung des kompletten Frameworks möglich.
Die Django Template-Engine ist eine Text-basierende Template-Engine entwickelt für das Django Webframework. Da die Template-Engine anfänglich nicht ohne Django verwendet werden konnte wurde unabhängig davon eine Kopie mit leichten Verbesserungen unter dem Namen Jinja entwickelt. Für die Version 1.0 dieser Template-Engine wurde das bestehende Konzept größtenteils über den Haufen geworfen und Unterstützung von Expressions hinzugefügt.
Der Hauptunterschied der beiden Template-Engines ist, dass die Django-Engine intern einen Baum von sogenannten Nodes besitzt und leicht erweitert werden kann. Jinja hingegen verwendet Python ähnliche Ausdrücke, die von einem Parser und Translator in Bytecode übersetzt werden. Vor-/Nachteil hier hier die starre Syntax, erhöhte Ausführungsgeschwindigkeit sowie höhere Flexibilität in den Templates selber.
Zusätzliche wichtige Unterschiede der beiden Engines:
- in Django kann man nur Funktionen aufrufen, die keine Parameter erwarten. Dies geschieht automatisch. In Jinja muss eine Funktion explizit aufgerufen werden und kann beliebige Argumente und Keyword-Argumente erwarten.
- Filter können in Django nur ein oder kein Argument erwarten.
- Jinja hat eine eingebaute Unterstützung für wiederverwendbare Teilbereiche (Macros) sowie das Darstellen von rekursiven Datenstrukturen.
Jinja erlaubt das Umdefinieren der Block Abgrenzern um die Darstellung der Syntax zu verwenden. So ist es möglich {% for item in seq %} gegen <% for item in seq %> auszutauschen.
page.html:
{% extends 'base.html' %}
{% block title %}Memberlist{% endblock %}
{% block content %}
<ul>
{% for user in users %}
<li><a href="{{ user.url|escape }}">{{ user.username|escape }}</a></li>
{% endfor %}
</ul>
{% endblock %}base.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{% block title %}{% endblock %} | My Webpage</title>
</head>
<body>
<div class="header">
<h1>My Webpage</h1>
</div>
<div class="body">
{% block body %}{% endblock %}
</div>
</body>
</html>