Определение «глобальной переменной» в шаблонах Django - PullRequest
6 голосов
/ 23 июня 2009

Я делаю что-то вроде:

{% 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 в начале каждого блока, он будет работать, но я не хочу «повторяться».

Кто-нибудь знает лучшее решение?

Ответы [ 5 ]

7 голосов
/ 23 июня 2009

Если URL относится к конкретному виду, вы можете передать URL из своего представления. Если URL должен быть действительно глобальным в ваших шаблонах, вы можете поместить его в контекстный процессор:

def object_url(request):
    return {'object_url': reverse('myapp.views.dashboard')}
2 голосов
/ 31 августа 2011

Похоже, что на это уже отвечали, но есть альтернатива. Одно дело использовать контекстный процессор, чтобы отслеживать что-то определенное извне шаблона, но иногда вы хотите подсчитать, сколько раз проходили два цикла, или что-то в этом роде. Есть еще один способ:

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
1 голос
/ 06 ноября 2015

Вы можете написать собственный тег шаблона:

@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 голосов
/ 23 июня 2009

В каждом унаследованном шаблоне любой код вне переопределения блоков не выполняется. Так что в вашем примере вы должны вызывать тег {% url %} внутри каждого блока или использовать контекстный процессор для установки «глобальной» переменной.

0 голосов
/ 23 июня 2009

Что ж, это немного злоупотребляет наследованием шаблонов, но вы можете использовать {{block.super}}, чтобы поместить object_url в ваши блоки.

Другими словами, в вашем шаблоне среднего уровня выполните:

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

А потом в своем блоке шаблоны используйте:

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

Это не очень хорошая идея, потому что она мешает вам положить что-то кроме {{ object_url }} в свой блок ... но это работает. Только не говори никому, что ты получил это от меня!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...