Pregunta

Encontre un enlace tener una etiqueta 'switch' en las plantillas de Django, pero me preguntaba si esto se puede lograr de alguna manera sin ella.¿Usando sólo lo que viene con Django?Básicamente, ¿hay otra forma que no sea usar múltiples declaraciones 'si' o 'igual'?

Gracias de antemano por cualquier consejo/sugerencia.

¿Fue útil?

Solución

Por desgracia, esto no es posible con el motor de plantillas de Django por defecto. Vas a tener que escribir algo feo como este para emular un interruptor.

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

o si sólo uno si el estado puede ser verdad y usted no necesita un defecto.

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

Por lo general, cuando el motor de plantillas no es lo suficientemente potente como para lograr lo que desea que esta es una señal de que el código se debe mover a la vista de Django en lugar de en la plantilla. Por ejemplo:

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

# Template
{{ val }}

Otros consejos

A partir de Django 1.4, hay {% elif %}:

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

Para los respondedores anteriores: Sin entender el caso de uso, usted ha hecho suposiciones y criticaron el interrogador. @Ber dice "por todo el lugar" que por cierto no está implícito en la pregunta. No es justo.

Tengo un caso en el que me gustaría hacer una declaración {% switch %} exactamente en un lugar en mi plantilla de Django. No sólo no es conveniente mover el equivalente de la sentencia switch en código Python, pero eso sería realmente hacer que tanto la vista y la plantilla más difícil de leer y tomar lógica condicional simple que pertenece en un solo lugar, que se dividió en dos lugares.

En muchos casos donde podría imaginar un {% switch %} (o un {% if %}) siendo útil, no usando uno requiere poner HTML en una vista. Eso es un pecado mucho peor y es por eso que existe {% if %} en el primer lugar. {% switch %} no es diferente.

Afortunadamente, Django es extensible y varias personas han implementado interruptor. Salida:

Interruptor etiqueta de plantilla

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

En una vista muy general, la necesidad de una instrucción switch es una señal de que hay una necesidad de crear nuevas clases y objetos que captan los diferentes "casos".

A continuación, en lugar de "swtich" ing por todo el lugar, sólo tiene que llamar a un método de objeto o hacer referencia a un atributo de objeto y su hecho.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top