2009-12-12 6 views
20

J'ai des modèles de ce styleDjango: Passage argument modèle parent

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

Ainsi lors du rendu, app2_templates étend app2_base_template qui s'étend main_template.

Ce que je dois faire, c'est que l'élément de nav correspondant soit en gras lorsque le template d'app2 est rendu (pour montrer à l'utilisateur où il se trouve).

Le plus simple serait si je pouvais passer une variable dans la partie {% block xxx%}. Est-ce possible?

Quelles sont les autres façons génériques?

+0

Avez-vous vérifié cela? http://stackoverflow.com/questions/1024168/django-is-there-a-better-way-to-bold-the-current-page-link – rinti

+2

Cette solution CSS semble très difficile à maintenir et nécessite d'ajouter des informations dans 3 endroits différents. – Boris

Répondre

41

Avez-vous essayé la balise template {% with%}?

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

Désolé, pas grokking cela. C'est dans base.html, et 'block.super' est-il destiné à faire référence à la barre de navigation ...? J'ai ma barre de navigation incluse dans ma base, * puis * mon "contenu de bloc" ... Comment est-il censé être mis en place pour que cela fonctionne? – Pureferret

+3

Un hack intéressant mais pas une solution complète. Le modèle parent doit être principalement entouré de '{% block content%}' pour que cela fonctionne et cela m'empêche d'écraser un autre bloc dans 'content'. – Kos

+0

La syntaxe a changé dans Django 1.11+, même si l'ancien est toujours supporté: https: //docs.djangoproject.com/en/1.11/ref/templates/builtins/#with. {% Avec 'myvar' comme expectedVarName% } => {% avec expectedVarName = 'myvar'%} – ThePhi

2

Les variables du modèle parent sont automatiquement incluses dans la portée de l'enfant. Votre titre dit que vous voulez passer une variable au parent, ce qui n'a pas de sens, car vous ne pouvez pas définir de variables dans les modèles. Si vous en avez besoin d'une variable dans le parent et l'enfant, déclarez-la simplement dans la vue.

8

Il n'existe aucun moyen direct de transmettre une variable dans l'arborescence d'héritage de modèle de la manière que vous décrivez. La façon dont les gens implémentent les barres de navigation qui mettent en évidence la page en cours est souvent ajustée à la nature du site lui-même. Cela dit, je l'ai vu deux approches communes:

L'approche low-tech

passer une variable dans le contexte du modèle qui indique l'onglet actif:

# 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> 

Plus -tech approche

Implémentez un custom template tag pour afficher votre barre de navigation. Avoir le tag prendre une variable qui indique quelle section est active:

<!-- 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 %} 

Vous pouvez vraiment devenir fou à partir de là. Vous pouvez constater que quelqu'un a déjà implémenté quelque chose qui fonctionnera pour vous sur djangosnippets.org.

+0

+1 pour l'approche high-tech. Il m'a fallu des recherches pour que cela fonctionne, des explications et des références sur les fichiers à mettre en place pour aider les gens dans le futur. – SpiRail

1

Malheureusement, je ne peux pas trouver un moyen propre.

Nous avons fini de mettre une étiquette dans chaque de base.html de l'application: (.. En fait, j'utilise deux Un ensemble par la base de l'application pour la principale nav un ensemble de pages d'applications pour la barre de navigation de l'application)

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

et un peu de magie JQuery dans le projet base.html

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

C'est un peu un hack, mais cette façon il est facile à comprendre et je ne ai besoin de faire des changements logiques sont ajoutés une fois plus d'applications.

2

L'impossibilité de passer les arguments lors de l'inclusion du modèle est l'un des nombreux échecs du système de gabarit Django.

J'ai dû faire face à un problème presque identique: les modèles imbriqués en profondeur nécessitaient que les modèles parents soient mis en forme/surlignés différemment.

solutions possibles:

  1. Utilisez un « super contexte » de routine qui définit un certain nombre de valeurs basées sur où dans la hiérarchie que vous êtes. C'est à dire. super_context = MySuperContext (requête, autre, valeurs, etc.), où super_context est une dict que vous passez à la vue (ou à RequestContext). C'est l'approche la plus Django-thnonic (?), Mais cela signifie que la logique de présentation a été repoussée dans les vues, ce qui me semble incorrect. Utilisez la balise de gabarit expr pour définir des valeurs dans les gabarits de niveau inférieur. Remarque: cela ne fonctionne que lorsque vous {% include%} un modèle car il doit être évalué avant l'inclusion. Vous ne pouvez pas le faire avec {% extends%} car cela doit être la première chose dans le modèle enfant.

  2. Passez à Jinja2 pour modéliser, au moins pour les vues où vous devez effectuer cette opération.

Une fois que vous avez ces valeurs défini, vous pouvez faire des choses comme ceci:

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

Cela rend la div class « foo » quand il est pas actif et « foo_active » quand il est. Style à goûter, mais n'ajoutez pas trop de cannelle. :-)

2

j'ai pris l'approche « low tech » Jarret Hardie dans un même heu ... contexte (oui, c'est un jeu de mots ... qui ne sera pas un sens parfait pour vous à moins que je vous dis que je ne faisait pas de VL mais fixait la couleur de la bordure des boutons afin de montrer lequel avait été pressé).

Mais ma version est un peu plus compacte je pense. Au lieu de définir une seule barre active de variables de contexte dans la vue, je renvoie un dictionnaire, mais toujours avec une seule paire clé-valeur: par ex. activebar = {'foo': 'actif'}. Puis, dans le modèle, j'écris simplement class = "{{activebar.foo}}" dans l'ancre foo, et de manière correspondante dans les autres ancres. Si seul activebar.foo est défini pour avoir la valeur "active" alors activebar.bar dans l'ancre de la barre ne fera rien. Peut-être que "échouer silencieusement" est le bon discours de Django. Et Bob est ton oncle.

EDIT: Oups ... quelques jours ont passé, et alors que ce que j'avais écrit ci-dessus a fonctionné pour moi un problème est apparu lorsque j'ai mis dans la barre de navigation une ancre avec une nouvelle fenêtre comme cible. Cela semblait être la cause d'un étrange problème: après avoir cliqué sur la nouvelle fenêtre (onglet dans Firefox) puis retourné à celui à partir duquel la nouvelle fenêtre a été lancée, des portions de l'affichage sous la barre de navigation devenaient vides chaque fois que je déplaçais curseur sur les éléments sur la barre de navigation --- sans cliquer sur quoi que ce soit. J'ai dû forcer un rafraîchissement d'écran en déplaçant la barre de défilement (pas un rechargement de page, bien que cela ait fonctionné parce qu'il implique un redessin de l'écran).

Je suis beaucoup trop bavard pour comprendre pourquoi cela pourrait arriver. Et il est possible que j'ai fait quelque chose d'autre qui a causé le problème. Mais ... j'ai trouvé une approche plus simple qui fonctionne parfaitement pour moi. Mes circonstances sont que chaque modèle enfant lancé à partir d'une vue doit afficher un élément de barre de navigation associé comme étant "actif". En effet, cet élément de la barre de navigation est celui qui a lancé la vue qui a lancé le modèle enfant --- le deal habituel.

Ma solution --- prenons un élément de navigation "login" à titre d'exemple --- est de mettre cela dans le modèle enfant qui contient le formulaire de connexion. Je l'ai mis en dessous du bloc de titre, mais je ne suppose pas le placement à l'importance. Ensuite, dans le modèle de parent qui contient la définition de barre de navigation, pour la balise li qui entoure l'ancre pour la connexion point navbar je mets ... eh bien, voici le code:

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

Ainsi, lorsque le modèle de l'enfant est rendu le parent affichera l'élément login navbar comme actif, et Bob est toujours votre oncle. L'approche de dictionnaire que j'ai décrite ci-dessus était de montrer laquelle d'une ligne de boutons avait été pressée, quand ils étaient tous sur le même modèle enfant. Cela fonctionne toujours pour moi et comme un seul modèle enfant est impliqué, je ne vois pas comment ma nouvelle méthode pour les navbars fonctionnerait dans cette circonstance. Notez qu'avec la nouvelle méthode pour les navbars, les vues ne sont même pas impliquées. Plus simple!

Questions connexes