在Django模板中定义“全局变量”

时间:2009-06-23 01:46:33

标签: django django-templates

我正在做类似的事情:

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

Django文档说url templatetag可以在上下文中定义一个变量,但是我在以下块中没有获得object_url的任何值。

如果我将url templatetag放在每个块的开头,它可以工作,但我不想“重复自己”。

任何人都知道更好的解决方案吗?

5 个答案:

答案 0 :(得分:7)

如果网址是特定于视图的,您可以从视图中传递该网址。如果您的模板中的网址需要真正全局,您可以将其放在a context processor:

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

答案 1 :(得分:2)

看起来之前已经回答了,但还有另一种选择。使用上下文处理器来跟踪从模板外部定义的内容是一回事,但有时您想要计算两个循环经历的次数,或者类似的东西。还有另一种方式:

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)

这允许您在如下模板中使用它:

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

答案 2 :(得分:1)

您可以编写自定义模板标记:

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

答案 3 :(得分:0)

嗯,这有点滥用模板继承,但您可以使用{{block.super}}将object_url放入块中。

换句话说,在您的中级模板中执行:

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

然后在您的块模板中使用:

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

这不是一个好主意,因为它会阻止你将{{ object_url }}以外的任何内容放入你的块中......但是它有效。只是不要告诉任何人你从我这里得到它!

答案 4 :(得分:0)

在每个继承的模板中,不会执行块重新定义之外的任何代码。因此,在您的示例中,您必须在每个块中调用{% url %}标记,或使用上下文处理器来设置“全局”变量。