Pergunta

Eu encontrei um ligação ter uma tag 'switch' em modelos de Django, mas eu queria saber se isso pode ser alguma forma conseguido sem ele. Usando apenas as coisas que vem com Django? Basicamente há outra maneira, em seguida, usando múltiplos 'se' ou declarações ifequal '?

Agradecemos antecipadamente por qualquer dicas / sugestões.

Foi útil?

Solução

Infelizmente, isso não é possível com o Django motor de modelo padrão. Você vai ter que escrever algo feio como este para emular um switch.

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

ou se apenas um se condição pode ser verdade e você não precisa de um padrão.

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

Normalmente, quando o modelo de motor não é potente o suficiente para realizar o que você quer este é um sinal de que o código deve ser movido à vista Django em vez de no modelo. Por exemplo:

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

# Template
{{ val }}

Outras dicas

A partir de Django 1.4, há {% elif %}:

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

Para os respondedores anteriores: Sem entender o caso de uso, você fez suposições e criticou o questionador. @Ber diz que "todo o lugar", que certamente não está implícito na pergunta. Não é justo.

Eu tenho um caso onde eu gostaria de fazer uma declaração {% switch %} em exatamente um lugar no meu modelo Django. Não só não é conveniente para mover o equivalente à instrução switch em código Python, mas que iria realmente fazer tanto a visão eo modelo mais difícil de ler e tomar lógica condicional simples que pertence em um lugar e dividi-lo em dois lugares.

Em muitos casos onde eu poderia imaginar um {% switch %} (ou um {% if %}) sendo útil, não usando um requer colocar HTML em uma exibição. Isso é um pecado muito pior e é por isso que existe {% if %} em primeiro lugar. {% switch %} não é diferente.

Felizmente, Django é extensível e várias pessoas têm implementado switch. Confira:

tag interruptor

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 ""

Em uma visão muito geral, a necessidade de uma instrução switch é um sinal de que há uma necessidade de criar novas classes e objetos que capturam os diferentes "casos".

Então, em vez de "swtich" ing em todo o lugar, você só precisa chamar um método de objeto ou fazer referência a um atributo de objeto e seu feito.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top