如何在Django模板中获得“switch-case”语句功能?

时间:2009-04-07 13:43:03

标签: django django-templates switch-statement case

我发现link在Django模板中有一个'switch'标签,但我想知道如果没有它可以以某种方式实现。只使用Django附带的东西?基本上还有其他方法,然后使用多个'if'或'ifequal'语句?

提前感谢任何提示/建议。

4 个答案:

答案 0 :(得分:47)

从Django 1.4开始,有{% elif %}

{% if a %}
  thing
{% elif b %}
  other thing
{% elif c %}
  another thing
{% endif %} 

答案 1 :(得分:21)

不幸的是,使用默认的Django模板引擎是不可能的。你必须写一些像这样丑陋的东西来模仿一个开关。

{% if a %}
    {{ a }}
{% else %}
    {% if b %}
        {{ b }}
    {% else %}
        {% if c %}
            {{ c }}
        {% else %}
            {{ default }}
        {% endif %}
    {% endif %}
{% endif %}

或者只有一个条件可以为真并且您不需要默认值。

{% if a %}
{{ a }}
{% endif %}
{% if b %}
{{ b }}
{% endif %}
{% if c %}
{{ c }}
{% endif %}

通常,当模板引擎功能不足以实现您想要的功能时,这表示应将代码移动到Django视图而不是模板中。例如:

# Django view
if a:
  val = a
elif b:
  val = b
elif c:
  val = c
else:
  val = default

# Template
{{ val }}

答案 2 :(得分:17)

对于之前的响应者:在不了解用例的情况下,您已经做出了假设并批评了提问者。 @Ber说“到处都是”,提问者肯定不会暗示这一点。不公平。

我有一个案例,我想在我的Django模板中的一个地方做一个{% switch %}语句。将switch语句的等价物移动到Python代码中不仅不方便,而且这实际上会使视图和模板更难以读取并采用属于一个地方的简单条件逻辑并将其拆分为两个位置。 / p>

在许多情况下,我可以想象{% switch %}(或{% if %})有用,不使用它需要将HTML放在视图中。这是一个更糟糕的罪,也是{% if %}首先存在的原因。 {% switch %}也不例外。

幸运的是,Django是可扩展的,并且有多个人实现了切换。退房:

Switch template tag

from django import template
from django.template import Library, Node, VariableDoesNotExist

register = Library()


@register.tag(name="switch")
def do_switch(parser, token):
    """
    The ``{% switch %}`` tag compares a variable against one or more values in
    ``{% case %}`` tags, and outputs the contents of the matching block.  An
    optional ``{% else %}`` tag sets off the default output if no matches
    could be found::

        {% switch result_count %}
            {% case 0 %}
                There are no search results.
            {% case 1 %}
                There is one search result.
            {% else %}
                Jackpot! Your search found {{ result_count }} results.
        {% endswitch %}

    Each ``{% case %}`` tag can take multiple values to compare the variable
    against::

        {% switch username %}
            {% case "Jim" "Bob" "Joe" %}
                Me old mate {{ username }}! How ya doin?
            {% else %}
                Hello {{ username }}
        {% endswitch %}
    """
    bits = token.contents.split()
    tag_name = bits[0]
    if len(bits) != 2:
        raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name)
    variable = parser.compile_filter(bits[1])

    class BlockTagList(object):
        # This is a bit of a hack, as it embeds knowledge of the behaviour
        # of Parser.parse() relating to the "parse_until" argument.
        def __init__(self, *names):
            self.names = set(names)
        def __contains__(self, token_contents):
            name = token_contents.split()[0]
            return name in self.names

    # Skip over everything before the first {% case %} tag
    parser.parse(BlockTagList('case', 'endswitch'))

    cases = []
    token = parser.next_token()
    got_case = False
    got_else = False
    while token.contents != 'endswitch':
        nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch'))

        if got_else:
            raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name)

        contents = token.contents.split()
        token_name, token_args = contents[0], contents[1:]

        if token_name == 'case':
            tests = map(parser.compile_filter, token_args)
            case = (tests, nodelist)
            got_case = True
        else:
            # The {% else %} tag
            case = (None, nodelist)
            got_else = True
        cases.append(case)
        token = parser.next_token()

    if not got_case:
        raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name)

    return SwitchNode(variable, cases)

class SwitchNode(Node):
    def __init__(self, variable, cases):
        self.variable = variable
        self.cases = cases

    def __repr__(self):
        return "<Switch node>"

    def __iter__(self):
        for tests, nodelist in self.cases:
            for node in nodelist:
                yield node

    def get_nodes_by_type(self, nodetype):
        nodes = []
        if isinstance(self, nodetype):
            nodes.append(self)
        for tests, nodelist in self.cases:
            nodes.extend(nodelist.get_nodes_by_type(nodetype))
        return nodes

    def render(self, context):
        try:
            value_missing = False
            value = self.variable.resolve(context, True)
        except VariableDoesNotExist:
            no_value = True
            value_missing = None

        for tests, nodelist in self.cases:
            if tests is None:
                return nodelist.render(context)
            elif not value_missing:
                for test in tests:
                    test_value = test.resolve(context, True)
                    if value == test_value:
                        return nodelist.render(context)
        else:
            return ""

答案 3 :(得分:2)

在一般情况下,需要一个switch语句表明需要创建捕获不同“案例”的新类和对象。

然后,您只需要调用一个对象方法或引用一个对象属性并完成所有操作,而不是“swtich”遍布整个地方。