2009-12-12 18 views
20

Ho modelli di questo stileDjango: Passando argomento di template padre

project 
- main_templates (including nav bar) 
-- app1 
--- app1_base_template 
--- app1_templates 
-- app2 
--- app2_base_template 
--- app2_templates 

Così durante il rendering, app2_templates estende app2_base_template che si estende main_template.

Quello che devo fare è avere la voce di navigazione corrispondente in grassetto quando viene eseguito il rendering del modello di app2 (per mostrare all'utente dove si trova).

Il più semplice sarebbe se potessi passare una variabile nella parte {% block xxx%}. È possibile?

Quali altri modi generici ci sono?

+0

Hai controllato? http://stackoverflow.com/questions/1024168/django-is-there-a-better-way-to-bold-the-current-page-link – rinti

+2

Questa soluzione CSS sembra molto difficile da mantenere e richiede di aggiungere informazioni in 3 posti diversi. – Boris

risposta

41

Hai provato il tag del modello {% con%}?

{% block content %} 
    {% with 'myvar' as expectedVarName %} 
    {{block.super}} 
    {% endwith %} 
{% endblock content %} 
+0

Siamo spiacenti, non groking questo. Questo è in base.html ed è 'block.super' destinato a fare riferimento alla barra di navigazione ...? Ho la mia barra di navigazione inclusa nella mia base, * quindi * il mio 'contenuto del blocco '... Come dovrebbe essere impostato affinché funzioni? – Pureferret

+3

Interessante mod, ma non una soluzione completa. Il modello principale deve essere per lo più circondato da '{% block content%}' perché funzioni e questo mi impedisce di sovrascrivere altri blocchi all'interno di 'content'. – Kos

+0

La sintassi modificata in Django 1.11+, anche se quella precedente è ancora supportata: https: //docs.djangoproject.com/en/1.11/ref/templates/builtins/#with. {% Con 'myvar' come expectedVarName% } => {% con expectedVarName = 'myvar'%} – ThePhi

2

Le variabili del modello principale vengono automaticamente incluse nell'ambito del figlio. Il tuo titolo dice che vuoi passare una variabile al genitore, il che non ha senso, dato che non puoi definire variabili nei template. Se ti serve una variabile sia nel genitore che nel bambino, devi solo dichiararla nella vista.

8

Non esiste un modo diretto per passare una variabile lungo l'albero di ereditarietà del modello come descritto. Il modo in cui le persone implementano le barre di navigazione che evidenziano la pagina corrente è spesso ottimizzato per la natura del sito stesso. Detto questo, ho visto due approcci comuni:

Il low-tech approccio

passare una variabile nel contesto modello che indica quale scheda è attiva:

# in views.py 
def my_view(request): 
    return render_to_response('app2_template.html', {"active_tab": "bar"}, 

<!-- Parent template --> 
<div id="navigation"> 
    <a href="/foo" {% ifequal active_tab "foo" %}class="active"{% endifequal %}>Foo</a> 
    <a href="/bar" {% ifequal active_tab "bar" %}class="active"{% endifequal %}>Bar</a> 
</div> 

Maggiore -tech approach

Implementare un custom template tag per eseguire il rendering della barra di navigazione. Chiedi al tag di prendere una variabile che indichi quale sezione è attiva:

<!-- Parent template --> 

<div id="navigation">{% block mainnav %}{% endblock %}</div> 

<!-- any child template --> 
{% load my_custom_nav_tag %} 
{% block mainnav %}{% my_custom_nav_tag "tab_that_is_active" %}{% endblock %} 

Da quel punto in poi puoi impazzire. Potresti scoprire che qualcuno ha già implementato qualcosa che funzionerà per te su djangosnippets.org.

+0

+1 per l'approccio high-tech. Mi sono preso qualche ricerca per farlo funzionare, qualche elaborazione e riferimenti su quali file mettere dove aiuterebbero alcune persone in futuro. – SpiRail

1

Purtroppo non riesco a trovare un modo pulito.

finito per mettere un tag in base.html di ogni app: (.. In realtà io uso due Un set da una base di app per la navigazione principale quello impostato da pagine dell'app per barra di navigazione dell'applicazione)

<span class="main_nav_bar_hint" id="2"></span> 

e un po 'di magia JQuery nel progetto base.html

$(document).ready(function() { $("#nav_menu_" + $(".main_nav_bar_hint").attr("id")).removeClass("normal").addClass("selected"); }) 

e' un po 'di un hack, ma in questo modo la sua facile da capire e ho solo bisogno di apportare modifiche logiche sono aggiunti una volta di più applicazioni.

2

L'incapacità di passare argomenti sull'inclusione dei modelli è una delle molte mancanze del sistema di template Django.

Ho dovuto affrontare un problema quasi identico: i modelli profondamente nidificati dovevano causare la formattazione/l'evidenziazione dei modelli padre in modo diverso.

Possibili soluzioni:

  1. utilizzare una routine di "super-contesto" che stabilisce una serie di valori in base a dove nella gerarchia sei. Cioè super_context = MySuperContext (richiesta, altri, valori, ecc.), dove super_context è un comando che si passa alla vista (oa RequestContext). Questo è l'approccio più Django-thónico (?), Ma significa che la logica della presentazione è stata repressa nei punti di vista, il che mi sembra sbagliato.

  2. Utilizzare il tag modello expr per impostare i valori nei modelli di livello inferiore. Nota: funziona solo quando {% include%} un modello perché deve essere valutato prima che l'inclusione si verifichi. Non puoi farlo con un {% estende%} perché deve essere la prima cosa nel modello figlio.

  3. Passare al modello Jinja2, almeno per le viste in cui è necessario eseguire questa operazione.

Una volta che avete questi valori impostati si possono fare cose come questa:

<div class="foo{% if foo_active%}_active{%endif%}"> stuff </div> 

Questo rende il div class "foo" quando non è attivo e "foo_active" quando è. Stile da gustare, ma non aggiungere troppa cannella. :-)

2

io ho preso l'approccio "low tech" di Jarret Hardie in una simile, err ... contesto (sì, è un gioco di parole ... che non renderà perfettamente senso per voi a meno che non vi dico che io non stava facendo navs ma impostando il colore del bordo dei pulsanti per mostrare quale era stato premuto).

Ma la mia versione è un po 'più compatta, penso. Invece di definire solo una semplice barra attiva della variabile di contesto nella vista, restituisco un dizionario, ma sempre con una sola coppia chiave-valore: ad es. activebar = {'foo': 'active'}.

Quindi nel modello scrivo semplicemente class = "{{activebar.foo}}" nell'ancora foo, e corrispondentemente negli altri ancore. Se solo activebar.foo è definito per avere il valore "attivo" allora activebar.bar nella barra di ancoraggio non farà nulla. Forse "fallire silenziosamente" è il giusto discorso di Django. E Bob è tuo zio.

EDIT: Oops ... un paio di giorni sono passati, e mentre quello che avevo scritto sopra ha funzionato per me un problema è apparso quando ho inserito nella barra di navigazione un ancoraggio con una nuova finestra come destinazione. Sembrava essere la causa di uno strano problema: dopo aver fatto clic sulla nuova finestra (scheda in Firefox) e poi tornare a quello da cui era stata lanciata la nuova finestra, le porzioni del display sotto la barra di navigazione diventavano vuote ogni volta che spostavo rapidamente la cursore sopra gli oggetti sulla barra di navigazione --- senza fare clic su nulla. Ho dovuto forzare il ridisegno dello schermo spostando la barra di scorrimento (non una pagina di ricaricamento, anche se anche questo ha funzionato perché comporta un ridisegno dello schermo).

Sono troppo un noob per capire perché potrebbe accadere. Ed è possibile che io abbia fatto qualcos'altro che ha causato il problema che in qualche modo è andato via. Ma ... ho trovato un approccio più semplice che funziona perfettamente per me. Le mie circostanze sono che ogni modello figlio che viene avviato da una vista dovrebbe causare la visualizzazione di un elemento della barra di navigazione come "attivo". In effetti, quell'elemento della barra di navigazione è quello che ha lanciato la vista che ha lanciato il modello figlio --- il solito affare.

La mia soluzione --- prendiamo come esempio una voce di "accesso" per la barra di navigazione --- è per inserire questo nel modello secondario che contiene il modulo di accesso.

{% block login %}active{% endblock %} 

L'ho messo sotto il cartiglio ma non credo che il posizionamento sia importante. Poi nel modello principale che contiene la definizione barra di navigazione, per il tag li che circonda l'ancora per la voce di accesso barra di navigazione ho messo ... beh, ecco il codice:

<li class="{% block login %}{% endblock %}"><a href="/mysite/login">Login</a></li> 

Così, quando il template figlio è resa la genitore mostrerà l'elemento della barra di navigazione come attivo, e Bob è ancora tuo zio.

L'approccio del dizionario che ho descritto sopra era per mostrare quale di una linea di pulsanti era stata premuta, quando erano tutti sullo stesso modello figlio. Funziona ancora per me e dal momento che è coinvolto un solo modello figlio, non vedo come il mio nuovo metodo per i navbar possa funzionare in quella circostanza. Si noti che con il nuovo metodo per le viste navbars non sono nemmeno coinvolte. Più semplice!