2016-06-15 19 views
5

Ho iniziato a utilizzare il modello personalizzato inclusion tags nei miei modelli django. Per esempio io ho un tag {% profilelink profile %} che inserisce un link a un profilo utente con una piccola versione della foto del profilo, in questo modo (profilelink.html):Modelli e spazi Django

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

Tuttavia, quando lo uso nel seguente frammento (sometemplate.html):

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

poi ho spazio tra il codice HTML prodotto dal secondo tag modello e la parentesi di chiusura. Questo spazio vuoto non è voluto. Viene dal carattere di fine riga finale nel file profilelink.html. Questo è un problema molto comune e la ricerca di Stackoverflow genera molte domande sugli spazi bianchi nei modelli in generale. Ecco un riepilogo delle soluzioni trovate finora e il motivo per cui non funzionano:

Alcuni di questi problemi sono risolvibili con il tag {% spaceless %}, ma non tutti. Questo tag rimuove solo gli spazi tra i tag, che non è il caso dell'esempio precedente.

Una possibile soluzione è di non avere un EOL finale in profilelink.html ma questo è altamente indesiderabile. Motivi: è generalmente cattivo stile; alcuni editor (vim) aggiungono automaticamente uno indietro per impostazione predefinita; è così che POSIX defines a line; potrebbe rendere infelici alcuni SCM; ecc.

Un'altra soluzione è passare a un altro motore di modello, come Jinja2, che può o non può risolvere questo problema. Ha il supporto per costrutti come {% ... -%} che mangiano il prossimo carattere EOL. Questo è utile in alcune situazioni, ma è anche inutile per il mio esempio sopra. Ma cambiare il backend di template per un così piccolo fastidio sembra un po 'eccessivo e aggiunge un'altra dipendenza. Mi piacerebbe attenermi a qualunque sia il modo standard "django" di fare le cose. A quanto pare, sembra che Jinja2 sia il nuovo default di Django.

Alcune persone hanno suggerito di utilizzare una classe middleware per rimuovere spazi bianchi ridondanti dall'HTML generato prima di essere inviati al browser. Questo è utile, ma solo per trasformare l'HTML in un modo che è funzionalmente equivalente, cioè la stessa semantica: verrà quindi visualizzato allo stesso modo nel browser. Non è quello che voglio, voglio un vero cambiamento nella semantica per farlo visualizzare correttamente. Questo è impossibile da implementare in una classe middleware generica. Ho bisogno di avere il controllo su questo caso per caso all'interno del modello stesso. Non mi interessa rendere l'HTML più carino, mi interessa che sia corretto in primo luogo.

C'è anche bug #2594 che è stato chiuso come WONTFIX con l'argomento (citazione) "il linguaggio dei template Django è abbastanza buono per la generazione di HTML, che non è sensibile a spazi bianchi". Nel mio parere questo è completamente sbagliato. L'HTML è molto sensibile agli spazi bianchi, semplicemente non gli importa quanto ce ne sia. Ci vuole molto se ci sono degli spazi bianchi o del tutto assenti.

Qualche domanda: esiste un modo corretto per risolvere questo problema in generale? (Uno che funziona sempre, non solo in alcune situazioni.)

(Le correzioni basate su CSS non contano, le sorprese copia/incolla sono malvagie.)

+2

Non è la soluzione più elegante, ma puoi prendere in considerazione l'uso di 'get_template' invece di' @ register' decorator, quindi rimuovere le nuove righe dalla stringa del modello prima di registrare il tag. A pensarci bene, potrebbe anche essere possibile fare di questo un decoratore. – Selcuk

+0

@Selcuk Ho provato a farlo ma non ci sono riuscito. Almeno non senza scavare negli interni del sistema di template, cosa che vorrei evitare. Se tu o qualcun altro puoi pubblicare una soluzione funzionante, sarebbe fantastico. – jlh

risposta

2

Credo che una soluzione è quello di utilizzare un simple_tag anziché un tag di inclusione, si spera senza troppa confusione.

presumo il tag è qualcosa di simile:

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

sarebbe possibile sostituire questo con

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

Non ho un Django progetto di fronte a me ora, quindi questo non è testato.

1

Questo è il migliore che ho trovato finora. Spero ancora in una soluzione migliore, ma per ora lo farà.

ho definito un filtro personalizzato come questo 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() 

e quindi utilizzarlo come segue:

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