2009-06-23 28 views
5

que estoy haciendo algo como:Definición de "variable global" en plantillas de Django

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

documentación de Django dice templatetag url puede definir una variable en su contexto, pero no obtener ningún valor para object_url en el siguiente bloques.

Si pongo el template de la url al comienzo de cada bloque, funciona, pero no quiero "repetirlo".

¿Alguien sabe una mejor solución?

Respuesta

7

Si la URL es específica de la vista, puede pasar la URL de su vista. Si la URL tiene que ser verdaderamente global en sus plantillas, se puede poner en a context processor:

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

+1, que' re rápido que yo – SingleNegationElimination

+0

Um, muchas vistas usan esta variable pero no todas. Además, estoy usando el mismo patrón para otro tipo de variables definidas por mis plantillas de etiquetas personalizadas. El caso anterior simplemente se simplificó, por lo que creo que no es apropiado adoptar su solución tal como está. – Achimnol

+3

Incluso si no se usa en todas las plantillas, no hace daño ponerlo en un procesador de contexto ... a menos que esté haciendo una búsqueda en la base de datos, por supuesto, en cuyo caso puede afectar el rendimiento del sitio. –

0

Bueno, esto es un poco abusivo de la herencia de plantillas, pero se puede utilizar para poner {{block.super}} object_url en sus bloques.

En otras palabras, en la plantilla de nivel medio hacer:

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

Y luego, en sus plantillas de bloques de usar:

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

No es una gran idea, ya que le impide poner nada además de {{ object_url }} en tu bloque ... pero funciona. ¡No le digas a nadie que lo obtuviste!

+0

Debo añadir que personalmente prefiero ser explícito y hacer la carga en cada plantilla. Me facilita ver exactamente de dónde provienen mis datos. –

0

En cada plantilla heredada, no se ejecuta ningún código fuera de la redefinición de bloques. Entonces, en su ejemplo, debe llamar a la etiqueta {% url %} dentro de cada bloque o usar el procesador de contexto para establecer la variable "global".

2

Parece que esto fue respondido antes, pero hay una alternativa. Una cosa es utilizar un procesador de contexto para realizar un seguimiento de algo definido desde fuera de la plantilla, pero a veces desea contar la cantidad de veces que pasan dos bucles, o algo así. Hay otra manera:

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) 

Esto le permite utilizarlo en una plantilla como esta:

{% 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

Se puede escribir una etiqueta de plantilla personalizada:

@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

He utilizado este enfoque yo mismo y funciona muy bien para el código y la legibilidad. Una variable global editada aleatoriamente en todas las plantillas puede ser muy difícil de depurar. Crear una máquina de estado usando una plantilla mantiene la lógica en un solo lugar, esto tiene muchos beneficios. –