Question

Je fais quelque chose comme:

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

La documentation de Django indique que l’URL templatetag peut définir une variable dans son contexte, mais je n’obtiens aucune valeur pour object_url dans les blocs suivants.

Si je place le gabarit d'URL au début de chaque bloc, cela fonctionne, mais je ne veux pas "me répéter".

Quelqu'un connaît une meilleure solution?

Était-ce utile?

La solution

Si l'URL est spécifique à la vue, vous pouvez la transmettre à partir de votre vue. Si l'URL doit être véritablement globale dans vos modèles, vous pouvez l'insérer dans un processeur de contexte:

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

Autres conseils

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 trace de quelque chose défini de l'extérieur du modèle, mais parfois vous voulez compter le nombre de fois où deux boucles passent, ou quelque chose comme ça. Il y a un autre moyen:

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

Vous pouvez écrire une balise de 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 ''

Eh bien, c’est un peu abusif de l’héritage des modèles, 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, effectuez les actions suivantes:

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

Et dans vos modèles de blocs, utilisez:

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

Ce n'est pas une bonne idée car cela vous empêche de mettre autre chose que {{object_url}} dans votre bloc ... mais cela fonctionne. Ne dites à personne que vous l'avez reçu de moi!

Dans chaque modèle hérité, tout code en dehors des redéfinitions de blocs n'est pas exécuté. Dans votre exemple, vous devez donc appeler la balise {% url%} à l'intérieur de chaque bloc ou utiliser un processeur de contexte pour définir le paramètre " global " variable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top