.. _templatetags: Templatetags ************ Mit den Templatetags, die Django zur Verfügung stellt, lässt sich gut arbeiten. Wirklich interessant ist aber die Möglichkeit eigene Templatetags zu schreiben. Wir wollen ein Templatetag für unser Projekt schreiben mit dem wir ermitteln können ob ein Benutzer der Autor eines Rezeptes ist. Außerdem soll es die Möglichkeit bieten einen alternativen Block zu rendern, wenn dies nicht der Fall ist. Das Templatetag dafür soll also so aussehen: .. code-block:: html+django {% is_author user recipe %} Der Benutzer ist Autor des Rezepts oder Redakteur. {% else %} Dieses Rezept darf von diesem Benutzer nicht bearbeitet werden. {% endis_author %} Das Templatetag ist ``is_author``. Das erste Argument ``user`` ist ein User Objekt. Das zweite Argument ``recipe`` ist eine Recipe Instanz. Ansonsten soll das Templatetag wie eine ``if``-Bedingung funktionieren. Die Verzeichnisstruktur für Templatetags ======================================== Templatetags müssen mit einer bestimmten Verzeichnisstruktur angelegt werden. Im Verzeichnis der Applikation wird ein neues Verzeichnis :file:`templatetags` erstellt. Darin wird die leere Datei :file:`__init__.py` angelegt, um das Verzeichnis als Python Package zu markieren. Als letztes legen wir eine Python Datei an, die das Modul für unsere Templatetags ist. Unser erstes Modul nennen wir :file:`recipes.py`. .. code-block:: bash recipes/ `-- templatetags |-- __init__.py `-- recipes.py Das Templatetag erstellen ========================= Ein Templatetag besteht immer aus einer Kompilierungsfunktion und einer Node. Die Kompilierungsfunktion parst das Tag mit Hilfe eines Parsers. Als Ergebnis gibt sie eine Instanz der Node zurück. Diese hat eine ``render``-Methode, die die Ausgabe erzeugt. Die Kompilierungsfunktion ------------------------- Zuerst erstellt du die Kompilierungsfunktion in der neu angelegten Datei :file:`recipes.py`: .. code-block:: python from django import template register = template.Library() @register.tag(name='is_author') def do_is_author(parser, token): """The ``{% is_author %}`` tag displays the first section, if the user is the author of the recipe or a staff member. Otherwise the second section is displayed. :: {% is_author user recipe %} The user is owner of this recipe or a staff member. {% else %} The user has no right to edit this recipe. {% endis_author %} """ try: tag_name, user, recipe = token.split_contents() except ValueError: raise template.TemplateSyntaxError( '%s requires a Recipe and an User as arguments' % token.contents.split()[0]) nodelist_true = parser.parse(('else', 'endis_author')) token = parser.next_token() if token.contents == 'else': nodelist_false = parser.parse(('endis_author',)) parser.delete_first_token() else: nodelist_false = template.NodeList() return IsAuthorNode(user, recipe, nodelist_true, nodelist_false) Der Renderer ------------ Danach schreibst du die Node, die die Ausgabe rendert. Dieser Code muss oberhalb der Funktion ``do_is_author`` stehen, denn sonst steht die Klasse ``IsAuthorNode`` nicht in der Funktion zur Verfügung. .. code-block:: python class IsAuthorNode(template.Node): def __init__(self, user, recipe, nodelist_true, nodelist_false): self.user = template.Variable(user) self.recipe = template.Variable(recipe) self.nodelist_true = nodelist_true self.nodelist_false = nodelist_false def render(self, context): try: user = self.user.resolve(context) recipe = self.recipe.resolve(context) except template.VariableDoesNotExist: return '' if recipe.author.id == user.id or user.is_staff: return self.nodelist_true.render(context) else: return self.nodelist_false.render(context) Das Templatetag nutzen ====================== Nun kannst du das neue Templatetag nutzen, zum Beispiel im Template :file:`recipes/templates/recipes/detail.html`. Dazu muss zuerst unser Templatetag geladen werden. Das machst du am besten im Kopf des Templates: .. code-block:: html+django {% load recipes %} .. note:: Der Bezeichner hinter dem ``load`` Templatetag ist immer der Name des Python Moduls, dass die Templatetags enthält, die geladen werden sollen (ohne die Endung ".py"). Das Python Modul muss sich im Verzeichnis ``templatetags`` einer installierten Applikation befinden. Dann ersetzt du diese beiden Zeilen: .. code-block:: html+django Rezept bearbeiten zurück zur Übersicht Mit dem neuen Templatetag: .. code-block:: html+django {% is_author user object %} Rezept bearbeiten {% else %} Bitte einloggen, um das Rezept zu bearbeiten. {% endis_author %} zurück zur Übersicht Django Apps zum einfachen Schreiben von Templatetags ==================================================== Da das Schreiben von Templatetags mit Django Bordmitteln recht umständlich ist, sind verschiedene Django Apps entstanden, die dies vereinfachen. Eine Übersicht gibt das `Templatetags Grid`_ auf Django Packages. Zwei der populärsten Templatetag Apps sind django-classy-tags_ und django-ttag_. .. _Templatetags Grid: http://www.djangopackages.com/grids/g/templatetags/ .. _django-classy-tags: http://pypi.python.org/pypi/django-classy-tags/ .. _django-ttag: http://pypi.python.org/pypi/django-ttag Weiterführende Links zur Django Dokumentation ============================================= * :djangodocs:`Eigene Templatetags und Filter schreiben `