Pregunta

Estoy haciendo algo como:

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

La documentación de Django dice que url templatetag puede definir una variable en contexto, pero no obtengo ningún valor para object_url en los siguientes bloques.

Si pongo la etiqueta de plantilla de URL al comienzo de cada bloque, funciona, pero no quiero "repetirme".

¿Alguien sabe una mejor solución?

¿Fue útil?

Solución

Si la URL es específica de la vista, puede pasar la URL desde su vista. Si la URL necesita ser verdaderamente global en sus plantillas, puede ponerla en un procesador de contexto:

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

Otros consejos

Parece que esto fue respondido antes, pero hay una alternativa. Una cosa es usar 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 forma:

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

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

Bueno, esto es un poco abusivo de la herencia de plantillas, pero podría usar {{block.super}} para poner object_url en tus bloques.

En otras palabras, en su plantilla de nivel medio haga:

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

Y luego en sus plantillas de bloque use:

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

No es una gran idea porque evita que coloques algo además de {{object_url}} en tu bloque ... pero funciona. ¡Simplemente no le digas a nadie que lo recibiste de mí!

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top