【问题标题】:django check existence of template context variabledjango 检查模板上下文变量是否存在
【发布时间】:2013-06-07 17:08:00
【问题描述】:

我正在编写一个 django 模板,我想区分一个上下文变量的 存在 与它是无、空等。我已经完成了我的作业,这似乎非常困难。具体来说,这就是我正在尝试做的事情

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

【问题讨论】:

    标签: django templates variables exists defined


    【解决方案1】:

    我最近遇到了同样的难题,在研究了{% 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 %}
    

    我不确定是否有更简单的方法来实现这一点,虽然我对这种方法不太满意,但它似乎在我的用例中运行良好。希望这会有所帮助!

    【讨论】:

    • 谢谢!我想这是许多不干净的解决方案中最干净的。
    【解决方案2】:

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

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

    现在如果 some_condition = False,比“for”循环不会在模板中运行,所以你不再需要“if”了。

    【讨论】:

      猜你喜欢
      • 2019-04-08
      • 2011-09-07
      • 2020-05-30
      • 2020-12-19
      • 2010-09-23
      • 2012-10-07
      • 2011-11-20
      • 1970-01-01
      • 2017-03-24
      相关资源
      最近更新 更多