Как получить функциональность оператора 'случая переключателя' в шаблонах Django?

Я думаю, вы не дождались события терминала, и основной поток завершается до того, как события будут доставлены вашему наблюдателю. Следующий тест проходит для меня с RxJava 1.0.14:

@Test
public void errorDelayed() {
    TestSubscriber<Object> ts = TestSubscriber.create();
    Observable.mergeDelayError(
            Observable.error(new RuntimeException()),
            Observable.just("Hello")
        )
        .subscribeOn(Schedulers.io()).subscribe(ts);

    ts.awaitTerminalEvent();

    ts.assertError(RuntimeException.class);
    ts.assertValue("Hello");
}
25
задан Czlowiekwidmo 7 April 2009 в 13:43
поделиться

4 ответа

К сожалению, это невозможно при использовании стандартного движка шаблонов 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 }}
21
ответ дан user27478 15 October 2019 в 14:55
поделиться

Начиная с Django 1.4, есть {% elif %}:

{% if a %}
  thing
{% elif b %}
  other thing
{% elif c %}
  another thing
{% endif %} 
49
ответ дан Steve Bennett 15 October 2019 в 14:55
поделиться

В самом общем виде необходимость в операторе switch является признаком того, что необходимо создать новые классы и объекты, которые фиксируют различные «случаи».

Затем, вместо «переключения» повсюду, вам нужно только вызвать метод объекта или ссылаться на атрибут объекта, и все готово.

2
ответ дан 28 November 2019 в 17:47
поделиться

To the previous responders: Without understanding the use case, you've made assumptions and criticized the questioner. @Ber says "all over the place" which is certainly not implied by the questioner. Not fair.

I have a case where I would like to do a {% switch %} statement in exactly one place in my Django template. Not only is it not convenient to move the equivalent of the switch statement into Python code, but that would actually make both the view and the template harder to read and take simple conditional logic that belongs in one place and split it into two places.

In many cases where I could imagine a {% switch %} (or an {% if %}) being useful, not using one requires putting HTML in a view. That's a far worse sin and is why {% if %} exists in the first place. {% switch %} is no different.

Fortunately, Django is extensible and multiple people have implemented switch. Check out:

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 ""
18
ответ дан 28 November 2019 в 17:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: