Comment obtenir toutes les fonctionnalités de l'instruction « switch-case » dans les modèles Django?

StackOverflow https://stackoverflow.com/questions/725771

Question

J'ai trouvé un lien pour avoir une balise « switch » dans les modèles de Django, mais je je me demandais si cela peut être en quelque sorte atteint sans elle. En utilisant seulement les choses qui vient avec Django? est en fait il y a d'autre moyen puis en utilisant plusieurs « si » ou déclarations « ifequal »?

Merci d'avance pour les conseils / suggestions.

Était-ce utile?

La solution

Malheureusement, cela est impossible avec le moteur par défaut de modèle Django. Vous devez écrire quelque chose de laid comme celui-ci émule un commutateur.

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

ou si une seule si la condition peut être vrai et vous n'avez pas besoin défaut.

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

En règle générale, lorsque le moteur de modèle n'est pas assez puissant pour accomplir ce que vous voulez que c'est un signe que le code doit être déplacé en vue Django plutôt que dans le modèle. Par exemple:

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

# Template
{{ val }}

Autres conseils

Au Django 1.4, il n'y a {% elif %}:

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

Pour les intervenants précédents: Sans comprendre le cas d'utilisation, vous avez fait des hypothèses et critiquait le questionneur. @Ber dit « partout » qui est certainement pas impliquée par le questionneur. Pas juste.

J'ai un cas où je voudrais faire une déclaration de {% switch %} exactement un endroit dans mon modèle Django. Non seulement est-il pas commode de déplacer l'équivalent de l'instruction switch en code Python, mais cela fait faire à la fois la vue et le modèle plus difficile à lire et à prendre logique simple conditionnelle qui appartient à un seul endroit et divisé en deux endroits.

Dans de nombreux cas où je pourrais imaginer un {% switch %} (ou un {% if %}) être utile, ne pas utiliser l'on exige de mettre HTML dans une vue. C'est bien pire péché et est la raison pour laquelle {% if %} existe en premier lieu. {% switch %} est pas différent.

Heureusement, Django est extensible et plusieurs personnes ont mis en place commutateur. Départ:

commutateur balise modèle

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

Dans une vue très générale, la nécessité d'une instruction switch est un signe qu'il est nécessaire de créer de nouvelles classes et les objets qui captent les différents « cas ».

Alors, au lieu de « swtich » ing dans tous les sens, il vous suffit d'appeler une méthode d'objet ou référencer un attribut d'objet et de votre fait.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top