Django检查模板上下文变量是否存在

5

我正在编写一个Django模板,我想区分上下文变量的存在与其为None、空等情况。我已经做了功课,但似乎很困难。具体来说,我想做到以下几点:

view 1:
...
if some_condition = True:
    context['letters'] = ['a', 'b', 'c'] # The list might also be empty or None in some cases
else
    context['numbers'] = [1, 2, 3] #This list might be empty or None in some cases

Template
...
<ul>
{% if letters %}
    {% for x in letter %}
        <li>{{x}}</li>
    {%endfor%}
{% else %}
    {%for x in numbers%}
        <li>{{x}}</li>
    {%endfor%}
</ul>

使用{% if %}存在一定风险,因为如果letters不存在或列表为空,则会失败。我希望即使letters为空(但在上下文中定义),也能使用它。

我在内置过滤器defaultdefault_if_none中也遇到了同样的问题。如何区分上下文变量的存在与其是其他内容(如None或Empty)?

2个回答

4

最近我也遇到了同样的问题,在研究了 {% if %} 标签的结构后,我得出了以下解决方案:

from django.template.base import VariableDoesNotExist
from django.template.defaulttags import IfNode
from django.template.smartif import IfParser, Literal

# Used as a value for ifdef and ifndef tags
undefined = object()

class IfDefLiteral(Literal):
    def eval(self, context):
        if not self.value in context:
            # Can't raise an exception here because Operator catches it
            return undefined

class IfDefParser(IfParser):
    def create_var(self, value):
        return IfDefLiteral(value)

class IfDefNode(IfNode):
    def __init__(self, defined=True, *args, **kwargs):
        self.defined = defined
        super(IfDefNode, self).__init__(*args, **kwargs)

    def __repr__(self):
        return "<%s>" % self.__class__.__name__

    def render(self, context):
        for condition, nodelist in self.conditions_nodelists:

            match = undefined
            if condition is not None:           # if / elif clause
                try:
                    match = condition.eval(context)
                except VariableDoesNotExist:
                    pass

            if condition is None or (  # else clause, always render
                (self.defined and match is not undefined) or
                (match is undefined and not self.defined)):
                return nodelist.render(context)

        return ''

def _gen_ifdef(parser, token, block_tokens, defined):
    # {% if ... %}
    bits = token.split_contents()[1:]
    condition = IfDefParser(bits).parse()
    nodelist = parser.parse(block_tokens)
    conditions_nodelists = [(condition, nodelist)]
    token = parser.next_token()

    # {% elif ... %} (repeatable)
    while token.contents.startswith(block_tokens[0]):
        bits = token.split_contents()[1:]
        condition = IfDefParser(bits).parse()
        nodelist = parser.parse(block_tokens)
        conditions_nodelists.append((condition, nodelist))
        token = parser.next_token()

    # {% else %} (optional)
    if token.contents == 'else':
        nodelist = parser.parse(block_tokens[-1:])
        conditions_nodelists.append((None, nodelist))
        token = parser.next_token()

    # {% endif %}
    assert token.contents == block_tokens[-1]

    return IfDefNode(defined, conditions_nodelists)

@register.tag
def ifdef(parser, token):
    """Check if variable is defined in the context

    Unlike the {% if %} tag, this renders the block if the variable(s)
    exist within the context, not only if they are truthy. That is, variables
    with None, 0 or [] values would also render the block.
    """
    return _gen_ifdef(parser, token, ('elifdef', 'else', 'endifdef'), True)

@register.tag
def ifndef(parser, token):
    """Check if variable is *not* defined in the context

    This is the opposite of {% ifdef %}.
    """
    return _gen_ifdef(parser, token, ('elifndef', 'else', 'endifndef'), False)

然后您可以像在模板中使用{% if %}标签一样使用它:

{% ifdef letters or numbers %}
    {# do something with letters or numbers #}
{% else %}
    {# variables are not defined here #}
{% endifdef %}

我不确定是否有更简单的方法来完成这个任务,虽然我对这种方法不是很满意,但在我的使用情况下似乎很有效。希望这可以帮到你!


谢谢!我想这是众多不干净解决方案中最干净的一个。 - sha

0

我不确定这种逻辑是否应该在模板中使用,因为它们应该是简单的。 我会解决它的方法就是在视图中添加(在“if”之前):

context['letters'] = False    #([]/None/False)
if some_condition = True:
    ...

现在如果some_condition = False,那么模板中的“for”循环将不会运行,因此您不再需要在那里使用“if”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接