Pug mit Django


pugdjangopythontemplate

Mit AngularJS ist pugjs (ehemals jade) bereits zum einem “must have” für mich geworden, es ist deutlich übersichtlicher, schlanker und erinnert mich an Python. Daher habe ich für diesen Blog versucht auch dessen Templates zu pugisieren. Dies sind meine Erfahrungen zu diesem Thema.

Installation

Zum Glück bin ich mit diesem Vorhaben nicht alleine und fand auch nach einer kurzen Suche das vielversprechendes Repository pypugjs auf Github. Es scheint so als wäre es ein Fork von pyjade den ich zuerst mit mäßigem Erfolg testete. Nach einem gewohnten:

pip install pypugjs

verlangt die App lediglich eine Neukonfiguration der Template Settings von Django, was auch irgendwie naheliegt. Die kompletten Template Einstellungen für diesen Blog sehen damit wie folgt aus:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'diary.libs.context_processor.base_context_processor',
                'diary.libs.context_processor.quick_admin_links_context_processor',
            ],
            'loaders': [
                ('pypugjs.ext.django.Loader', (
                    'django.template.loaders.filesystem.Loader',
                    'django.template.loaders.app_directories.Loader',
                ))
            ],
            'builtins': ['pypugjs.ext.django.templatetags'],
        },
    },
]

Wichtig hier ist das entfernen oder deaktivieren der APP_DIRS Einstellung, da diese nicht zusammen mit den loaders verwendet werden kann. Wie ihr aber seht, ist diese Funktion dem pypugjs Loader untergeordnet.

Soweit so gut. Was in der Readme des Projektes jedoch meiner Meinung nach etwas zu kurz gekommen war, sind die Django spezifischen PugTags, sodass sich ein erster Erfolg noch etwas hinzog. Um anderen das Rätselraten oder Suchmaschinen bemühen etwas zu ersparen dachte ich mir ich zeige hier das Ergebnis Template, in dem folgende Tags und Filter von Django untergebracht sind: Template Extension, Templatetags, Loops, Conditions und Variablen.

- extends "base.html"
- load blog_extras
- load thumbnail
- load i18n

block title
    | {{post.title}}
    block description
    | {{post.abstract}}

    block open_graph
    meta(property="og:title" content="{{post.title}}")
    meta(property="og:type" content="article")
    meta(property="article:published_time" content="{{post.created|date:'c'}}")
    meta(property="article:modified_time" content="{{post.updated|date:'c'}}")
    for tag in post.tags.all
        meta(property="article:tag" content="{{ tag }}")

        block container
    .row
        .col.col-lg-12
            pre.plain {{post.data}}
            .markdown.styled
                {{post.data|markdown}}
                .clearfix
            if post.diff
                hr
                h2 Git Diff
                diff.styled
                pre.plain(id="diffBlock")
            hr
            h2 {% trans "Meta space" %}
            dl.dl-horizontal
                dt {% trans "Created" %}
                dd {{ post.created|date:'d.m.Y H:i' }}
                dt {% trans "Updated" %}
                dd {{ post.updated|date:'d.m.Y H:i' }}
                dt {% trans "Tags" %}
                dd {{ post.tags.all|join:', ' }}
                dt {% trans "Perma URL" %}
                dd
                    a(href="{{ BASE_URL }}{{ post.get_absolute_url }}") {{ post.get_absolute_url }}

Was mir besonders gut in der Pug Unterstütztung für Django gefällt ist, dass selbst der Django Code besser aussieht und auch Blöcke in typischer Pug Manier nicht mehr geschlossen werden müssen. 👍

Zum Vergleich, hier das HTML Template

{% extends "base.html" %}
{% load blog_extras %}
{% load thumbnail %}
{% load i18n %}

{% block title %}{{post.title}}{% endblock title %}
{% block description %}{{post.abstract}}{% endblock description %}

{% block open_graph %}
    <meta property="og:title" content="{{post.title}}">
    <meta property="og:type" content="article">
    <meta property="article:published_time" content="{{post.created|date:'c'}}">
    <meta property="article:modified_time" content="{{post.updated|date:'c'}}">
    {% for tag in post.tags.all %}
        <meta property="article:tag" content="{{ tag }}">
    {% endfor %}
    {% endblock open_graph %}


{% block container %}
    <div class="row">
        <div class="col col-lg-12">
            <pre class="plain">{{post.data}}</pre>
            <div class="markdown styled">
                {{post.data|markdown}}
                <div class="clearfix"></div>
            </div>
            {% if post.diff %}
                <hr>
                <h2>Git Diff</h2>
                <diff class="styled"></diff>
                <pre class="plain" id="diffBlock"></pre>
            {% endif %}
            <hr>
            <h2>{% trans "Meta space" %}</h2>
            <dl class="dl-horizontal">
                <dt>{% trans "Created" %}</dt>
                <dd>{{ post.created|date:'d.m.Y H:i' }}</dd>
                <dt>{% trans "Updated" %}</dt>
                <dd>{{ post.updated|date:'d.m.Y H:i' }}</dd>
                <dt>{% trans "Tags" %}</dt>
                <dd>{{ post.tags.all|join:', ' }}</dd>
                <dt>{% trans "Perma URL" %}</dt>
                <dd><a href="{{ BASE_URL }}{{ post.get_absolute_url }}">{{ post.get_absolute_url }}</a></dd>
            </dl>
        </div>
    </div>
{% endblock container %}

Übersetzungen

Nachdem ich mich bereits fertig wähnte und das Update deployte, merkte ich jedoch, dass die Trans Tag für die Übersetzung nicht mehr extrahiert wurden. Durch einen kurzen Stackoverflow Tipp entschied ich mich dafür meinen Fabric Wrapper um Makemessages um den Parameter für Zu untersuchende Dateienendungen zu setzen, was auch reibungslos ging und zum gewünschten Ergebnis führte.

Soweit hat alles gut geklappt und ich konnte pug templates wie geplant verwenden. Erst später bemerkte ich, dass makemessages über den django admin trans-Tags nicht mehr gefunden und extrahiert wurden. Über Stackoverflow habe ich einen Hinweis auf den -e Parameter gefunden, sodass mein Fabric-Befehl nur noch wie folgt angepasst werden musste:

django-admin makemessages --ignore .virtualenv --ignore fixtures -a --no-location -e html,pug,py,txt

Sonstiges

Einen weiteren Tipp eines alten Freundes möchte ich an dieser Stelle der Vollständigkeit halber und da ich nicht selbst darauf gekommen bin, noch erwähnen: Für alle die umfangreichere HTML Templates in Pug wandeln wollen, gibt es natürlich auch einen Onlinedienst, der dies zuverlässig erfüllt: htm2jade.org. Ich habe htm2jade.org gewählt, da man bei diesem Dienst auch die Tab Einstellungen vornehmen kann und so ein paar Sekunden im Editor spart.

Ich kann nur alle Django Entwickler ermutigen diesen Schritt für ihre nicht Rest Projekte zu gehen, Pug ist ein tolles Werkzeug.

Pug – robust, elegant, feature rich template engine for Node.js

https://pugjs.org

Dem kann ich mich nur anschließen 👻

Meta-level


Article language
German
Article date
Feb. 24, 2017
Updated at
July 11, 2021