2009-06-23 3 views
5

que je fais quelque chose comme:Définition « variable globale » dans Django templates

{% extends 'base.html' %} 
{% url myapp.views.dashboard object as object_url %} 
{% block sidebar %} 
... {{ object_url }} ... 
{% endblock %} 
{% block content %} 
... {{ object_url }} ... 
{% endblock %} 

documentation Django dit templatetag url peut définir une variable dans le contexte, mais je ne reçois aucune valeur pour ne pas object_url dans ce qui suit des blocs.

Si je mets l'url templatetag au début de chaque bloc, cela fonctionne, mais je ne veux pas me «répéter».

Quelqu'un connaît une meilleure solution?

Répondre

7

Si l'URL est spécifique à la vue, vous pouvez transmettre l'URL de votre vue. Si l'URL doit être véritablement mondiale dans vos modèles, vous pouvez le mettre dans a context processor:

def object_url(request): 
    return {'object_url': reverse('myapp.views.dashboard')} 
+0

+1, vous re plus vite que moi. – SingleNegationElimination

+0

Euh, de nombreuses vues utilisent cette variable mais pas toutes. En outre, j'utilise le même modèle pour un autre type de variables définies par mes templatetags personnalisés. Le cas ci-dessus est simplement simplifié, donc je pense qu'il n'est pas approprié d'adopter votre solution telle qu'elle est. – Achimnol

+3

Même s'il n'est pas utilisé dans tous les gabarits, il ne fait aucun mal à le placer dans un processeur de contexte ... à moins qu'il ne fasse une recherche de base de données, auquel cas cela peut affecter les performances du site. –

0

Eh bien, ce genre d'abus est de l'héritage de modèle, mais vous pouvez utiliser {{block.super}} pour mettre object_url dans vos blocs.

En d'autres termes, dans votre modèle de niveau intermédiaire font:

{% block sidebar %}{{ object_url }}{% endblock %} 
{% block content %}{{ object_url }}{% endblock %} 

Et puis dans vos modèles de USAgE:

{% block sidebar %} 
... {{ block.super }}... 
{% endblock %} 

Ce n'est pas une bonne idée, car il vous empêche de mettre quoi que ce soit Outre {{ object_url }} dans votre bloc ... mais cela fonctionne. Juste ne dites à personne que vous l'avez eu de moi!

+0

Je devrais ajouter que personnellement je préfère être explicite et faire la charge dans chaque modèle. Cela me permet de voir plus facilement d'où proviennent mes données. –

0

Dans tout modèle hérité, tout code hors redéfinitions de blocs n'est pas exécuté. Ainsi, dans votre exemple, vous devez appeler le marqueur {% url %} à l'intérieur de chaque bloc ou utiliser le processeur de contexte pour définir la variable "globale".

2

On dirait que cela a déjà été répondu, mais il existe une alternative. C'est une chose d'utiliser un processeur de contexte pour garder une trace de quelque chose de défini à l'extérieur du modèle, mais parfois vous voulez compter le nombre de fois que deux boucles traversent, ou quelque chose comme ça. Il y a une autre façon:

class GlobalVariable(object): 
    def __init__(self, varname, varval): 
    self.varname = varname 
    self.varval = varval 
    def name(self): 
    return self.varname 
    def value(self): 
    return self.varval 
    def set(self, newval): 
    self.varval = newval 

class GlobalVariableSetNode(template.Node): 
    def __init__(self, varname, varval): 
    self.varname = varname 
    self.varval = varval 
    def render(self, context): 
    gv = context.get(self.varname, None) 
    if gv: 
     gv.set(self.varval) 
    else: 
     gv = context[self.varname] = GlobalVariable(self.varname, self.varval) 
    return '' 
def setglobal(parser, token): 
    try: 
    tag_name, varname, varval = token.contents.split(None, 2) 
    except ValueError: 
    raise template.TemplateSyntaxError("%r tag requires 2 arguments" % token.contents.split()[0]) 
    return GlobalVariableSetNode(varname, varval) 
register.tag('setglobal', setglobal) 

class GlobalVariableGetNode(template.Node): 
    def __init__(self, varname): 
    self.varname = varname 
    def render(self, context): 
    try: 
     return context[self.varname].value() 
    except AttributeError: 
     return '' 
def getglobal(parser, token): 
    try: 
    tag_name, varname = token.contents.split(None, 1) 
    except ValueError: 
    raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0]) 
    return GlobalVariableGetNode(varname) 
register.tag('getglobal', getglobal) 

class GlobalVariableIncrementNode(template.Node): 
    def __init__(self, varname): 
    self.varname = varname 
    def render(self, context): 
    gv = context.get(self.varname, None) 
    if gv is None: 
     return '' 
    gv.set(int(gv.value()) + 1) 
    return '' 
def incrementglobal(parser, token): 
    try: 
    tag_name, varname = token.contents.split(None, 1) 
    except ValueError: 
    raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0]) 
    return GlobalVariableIncrementNode(varname) 
register.tag('incrementglobal', incrementglobal) 

Cela vous permet de l'utiliser dans un modèle comme celui-ci:

{% setglobal ii 0 %} 
... 
{% for ... %} 
    {% incrementglobal ii %} 
    current={% getglobal ii %} 
{% endfor %} 
... 
{% for ... %} 
    {% incrementglobal ii %} 
    current={% getglobal ii %} 
{% endfor %} 
... 
total of 2 loops={% getglobal ii %} 
... 
{% setglobal ii 0 %} 
... 
do something else now that {% getglobal ii %} is back to 0 
1

Vous pouvez écrire un tag modèle personnalisé:

@register.simple_tag(takes_context=True) 
def set_global_context(context, key, value): 
    """ 
    Sets a value to the global template context, so it can 
    be accessible across blocks. 

    Note that the block where the global context variable is set must appear 
    before the other blocks using the variable IN THE BASE TEMPLATE. The order 
    of the blocks in the extending template is not important. 

    Usage:: 
     {% extends 'base.html' %} 

     {% block first %} 
      {% set_global_context 'foo' 'bar' %} 
     {% endblock %} 

     {% block second %} 
      {{ foo }} 
     {% endblock %} 
    """ 
    context.dicts[0][key] = value 
    return '' 
+0

J'ai moi-même utilisé cette approche et cela fonctionne très bien pour le code et la lisibilité. Une variable globale éditée aléatoirement dans les modèles peut être très difficile à déboguer. La création d'une machine d'état à l'aide d'un modèle conserve la logique au même endroit, ce qui présente de nombreux avantages. –