Commit 19cbdf8c authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Fixed #17348 -- Implemented {% elif %}. Refs #3100.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@17187 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 959f78b3
Loading
Loading
Loading
Loading
+51 −26
Original line number Diff line number Diff line
@@ -250,31 +250,37 @@ class IfEqualNode(Node):
        return self.nodelist_false.render(context)

class IfNode(Node):
    child_nodelists = ('nodelist_true', 'nodelist_false')

    def __init__(self, var, nodelist_true, nodelist_false=None):
        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
        self.var = var
    def __init__(self, conditions_nodelists):
        self.conditions_nodelists = conditions_nodelists

    def __repr__(self):
        return "<If node>"
        return "<IfNode>"

    def __iter__(self):
        for node in self.nodelist_true:
            yield node
        for node in self.nodelist_false:
        for _, nodelist in self.conditions_nodelists:
            for node in nodelist:
                yield node

    @property
    def nodelist(self):
        return NodeList(node for _, nodelist in self.conditions_nodelists for node in nodelist)

    def render(self, context):
        for condition, nodelist in self.conditions_nodelists:

            if condition is not None:           # if / elif clause
                try:
            var = self.var.eval(context)
                    match = condition.eval(context)
                except VariableDoesNotExist:
            var = None
                    match = None
            else:                               # else clause
                match = True

        if var:
            return self.nodelist_true.render(context)
        else:
            return self.nodelist_false.render(context)
            if match:
                return nodelist.render(context)

        return ''

class RegroupNode(Node):
    def __init__(self, target, expression, var_name):
@@ -825,6 +831,8 @@ def do_if(parser, token):

        {% if athlete_list %}
            Number of athletes: {{ athlete_list|count }}
        {% elif athlete_in_locker_room_list %}
            Athletes should be out of the locker room soon!
        {% else %}
            No athletes.
        {% endif %}
@@ -832,8 +840,9 @@ def do_if(parser, token):
    In the above, if ``athlete_list`` is not empty, the number of athletes will
    be displayed by the ``{{ athlete_list|count }}`` variable.

    As you can see, the ``if`` tag can take an option ``{% else %}`` clause
    that will be displayed if the test fails.
    As you can see, the ``if`` tag may take one or several `` {% elif %}``
    clauses, as well as an ``{% else %}`` clause that will be displayed if all
    previous conditions fail. These clauses are optional.

    ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
    variables or to negate a given variable::
@@ -871,16 +880,32 @@ def do_if(parser, token):

    Operator precedence follows Python.
    """
    # {% if ... %}
    bits = token.split_contents()[1:]
    var = TemplateIfParser(parser, bits).parse()
    nodelist_true = parser.parse(('else', 'endif'))
    condition = TemplateIfParser(parser, bits).parse()
    nodelist = parser.parse(('elif', 'else', 'endif'))
    conditions_nodelists = [(condition, nodelist)]
    token = parser.next_token()

    # {% elif ... %} (repeatable)
    while token.contents.startswith('elif'):
        bits = token.split_contents()[1:]
        condition = TemplateIfParser(parser, bits).parse()
        nodelist = parser.parse(('elif', 'else', 'endif'))
        conditions_nodelists.append((condition, nodelist))
        token = parser.next_token()

    # {% else %} (optional)
    if token.contents == 'else':
        nodelist_false = parser.parse(('endif',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfNode(var, nodelist_true, nodelist_false)
        nodelist = parser.parse(('endif',))
        conditions_nodelists.append((None, nodelist))
        token = parser.next_token()

    # {% endif %}
    assert token.contents == 'endif'

    return IfNode(conditions_nodelists)


@register.tag
def ifchanged(parser, token):
+9 −2
Original line number Diff line number Diff line
@@ -366,6 +366,8 @@ block are output::

    {% if athlete_list %}
        Number of athletes: {{ athlete_list|length }}
    {% elif athlete_in_locker_room_list %}
        Athletes should be out of the locker room soon!
    {% else %}
        No athletes.
    {% endif %}
@@ -373,8 +375,13 @@ block are output::
In the above, if ``athlete_list`` is not empty, the number of athletes will be
displayed by the ``{{ athlete_list|length }}`` variable.

As you can see, the ``if`` tag can take an optional ``{% else %}`` clause that
will be displayed if the test fails.
As you can see, the ``if`` tag may take one or several `` {% elif %}``
clauses, as well as an ``{% else %}`` clause that will be displayed if all
previous conditions fail. These clauses are optional.

.. versionadded:: 1.4

The ``if`` tag now supports ``{% elif %}`` clauses.

Boolean operators
^^^^^^^^^^^^^^^^^
+2 −0
Original line number Diff line number Diff line
@@ -484,6 +484,8 @@ Django 1.4 also includes several smaller improvements worth noting:
  be able to retrieve a translation string without displaying it but setting
  a template context variable instead.

* The :ttag:`if` template tag now supports ``{% elif %}`` clauses.

* A new plain text version of the HTTP 500 status code internal error page
  served when :setting:`DEBUG` is ``True`` is now sent to the client when
  Django detects that the request has originated in JavaScript code
+12 −1
Original line number Diff line number Diff line
@@ -394,7 +394,7 @@ class Templates(unittest.TestCase):
        try:
            t = Template("{% if 1 %}lala{% endblock %}{% endif %}")
        except TemplateSyntaxError, e:
            self.assertEqual(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'")
            self.assertEqual(e.args[0], "Invalid block tag: 'endblock', expected 'elif', 'else' or 'endif'")

    def test_templates(self):
        template_tests = self.get_template_tests()
@@ -823,6 +823,17 @@ class Templates(unittest.TestCase):
            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),

            'if-tag04': ("{% if foo %}foo{% elif bar %}bar{% endif %}", {'foo': True}, "foo"),
            'if-tag05': ("{% if foo %}foo{% elif bar %}bar{% endif %}", {'bar': True}, "bar"),
            'if-tag06': ("{% if foo %}foo{% elif bar %}bar{% endif %}", {}, ""),
            'if-tag07': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}", {'foo': True}, "foo"),
            'if-tag08': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}", {'bar': True}, "bar"),
            'if-tag09': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{% endif %}", {}, "nothing"),
            'if-tag10': ("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% else %}nothing{% endif %}", {'foo': True}, "foo"),
            'if-tag11': ("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% else %}nothing{% endif %}", {'bar': True}, "bar"),
            'if-tag12': ("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% else %}nothing{% endif %}", {'baz': True}, "baz"),
            'if-tag13': ("{% if foo %}foo{% elif bar %}bar{% elif baz %}baz{% else %}nothing{% endif %}", {}, "nothing"),

            # Filters
            'if-tag-filter01': ("{% if foo|length == 5 %}yes{% else %}no{% endif %}", {'foo': 'abcde'}, "yes"),
            'if-tag-filter02': ("{% if foo|upper == 'ABC' %}yes{% else %}no{% endif %}", {}, "no"),