2016-06-15 3 views
5

Ich begann mit benutzerdefinierten inclusion tags innerhalb meiner Django Vorlagen. Zum Beispiel habe ich einen {% profilelink profile %}-Tag, das eine Verbindung zu einem Benutzerprofil fügt zusammen mit einer kleinen Version des Bildes Profil, wie so (profilelink.html):Django Vorlagen und Leerzeichen

<a href='{% url ... %}'><img src='{{ ... }}' alt='...'> {{ profile.name }}</a> 

Allerdings, wenn ich es verwenden, in der folgender Ausschnitt (sometemplate.html):

<p>Owned by {% profilelink owner %} (uploaded by {% profilelink uploader %})</p> 

Dann bekomme ich Leerzeichen zwischen dem HTML durch den zweiten Template-Tag und die schließenden Klammer erzeugt. Dieser Leerraum ist unerwünscht. Es kommt vom letzten Zeilenumbruchzeichen in der Datei profilelink.html. Dies ist ein sehr häufiges Problem und die Suche in Stackoverflow führt zu vielen Fragen über Leerzeichen in Vorlagen im Allgemeinen. Hier ist eine Zusammenfassung der bisher gefundenen Lösungen und warum sie nicht funktionieren:

Einige dieser Probleme sind mit dem Tag {% spaceless %} lösbar, aber nicht alle von ihnen. Dieses Tag entfernt nur die Leerzeichen zwischen Tags, was im obigen Beispiel nicht der Fall ist.

Eine mögliche Lösung ist, kein endgültiges EOL in profilelink.html zu haben, aber das ist höchst unerwünscht. Gründe: Es ist im Allgemeinen schlechter Stil; Einige Editoren (vim) fügen standardmäßig standardmäßig eine zurück. das ist, wie POSIX defines a line; es könnte einige SCMs unglücklich machen; etc.

Eine andere Lösung ist das Wechseln zu einer anderen Template-Engine, wie Jinja2, die dieses Problem lösen kann oder auch nicht. Es hat Unterstützung für Konstrukte wie {% ... -%}, die das nächste EOL-Zeichen essen. Dies ist in einigen Situationen nützlich, ist aber auch für mein Beispiel oben nutzlos. Aber das Templating-Backend für solch ein kleines Ärgernis zu wechseln, scheint etwas übertrieben zu sein und fügt eine weitere Abhängigkeit hinzu. Ich würde gerne bei dem bleiben, was der Standard "Django" ist. Es gibt anscheinend Pläne, Jinja2 zum neuen Django Standard zu machen.

Einige Leute haben vorgeschlagen, eine Middleware-Klasse zu verwenden, um überflüssige Leerzeichen aus dem generierten HTML zu entfernen, bevor sie an den Browser gesendet werden. Dies ist nützlich, aber nur zum Transformieren des HTML in einer Weise, die funktional äquivalent ist, d. H. Dieselbe Semantik: sie wird dann immer noch auf die gleiche Weise im Browser angezeigt. Das ist nicht was ich will, ich möchte eine tatsächliche Änderung in der Semantik, um es richtig angezeigt zu haben. Dies ist in einer generischen Middleware-Klasse nicht möglich. Ich muss von Fall zu Fall die Kontrolle über das Template selbst haben. Es macht mir nichts aus, den HTML-Code hübscher zu machen, ich sorge mich darum, dass er von Anfang an richtig ist.

Es gibt auch bug #2594 ist, die als WONTFIX mit dem Argument (Zitat) geschlossen wurde „die Template-Sprache Django ist gut genug für HTML zu erzeugen, die nicht empfindlich auf Leerzeichen“. In meiner Sicht ist das einfach total falsch. HTML ist sehr empfindlich auf Leerzeichen, es ist einfach egal, wie viel davon ist. Es ist sehr wichtig, ob es irgendwelche Leerzeichen oder gar keine gibt.

Einige meine Frage ist: Gibt es einen gesunden Weg, um dieses Problem im Allgemeinen zu beheben? (Eine, die immer funktioniert, nicht nur in einigen Situationen.)

(Alle CSS-basierten Korrekturen zählen nicht. Kopieren/Einfügen Überraschungen sind böse.)

+2

Nicht die eleganteste Lösung, aber Sie können 'get_template' anstelle von' @register' Dekorator in Erwägung ziehen und dann die Zeilenvorschübe aus der Vorlagenzeichenfolge entfernen, bevor Sie Ihr Tag registrieren. Bei einem zweiten Gedanken könnte es auch möglich sein, dies zu einem Dekorateur zu machen. – Selcuk

+0

@Selcuk Ich habe versucht, dies zu tun, ist aber nicht gelungen. Zumindest nicht ohne in die Interna des Template-Systems zu stoßen, die ich gerne vermeiden würde. Wenn Sie oder jemand anderes eine funktionierende Lösung veröffentlichen kann, wäre das großartig. – jlh

Antwort

2

Ich glaube, eine Lösung ist ein simple_tag anstelle eines Einschluss-Tags zu verwenden, hoffentlich ohne zu viel Unordnung.

Ich nehme Ihren Tag so etwas wie diese: jetzt

@register.inclusion_tag('profilelink.html') 
def profilelink(user): 
    return {"profile": user} 

Wäre es möglich, das ich nicht habe ein Django-Projekt vor mir mit

from django.template.loader import render_to_string 

@register.simple_tag 
def profilelink(user): 
    t = render_to_string("profilelink.html", {"profile": user}) 
    return t.strip() 

zu ersetzen, Das ist also nicht getestet.

1

Das ist das Beste, was ich bisher gemacht habe. Ich hoffe immer noch auf eine bessere Lösung, aber für jetzt wird es tun.

I definiert einen benutzerdefinierten Filter wie dies in base/templatetags/basetags.yp (taken from this answer):

from django import template 
from django.template.defaultfilters import stringfilter 

register = template.Library() 

@register.filter 
@stringfilter 
def trim(value): 
    return value.strip() 

Und es dann wie folgt verwenden:

{% load basetags %} 
<p>Owned by {% profilelink owner %} (uploaded by 
{% filter trim %}{% profilelink uploader %}{% endfilter %})</p>