commit a387e97f4faf7f2237297933aa32f3b2d88c3e7f
Author: Matthias Kestenholz <mk@spinlock.ch>
Date:   Thu Oct 7 16:12:05 2010 +0200

    WIP

diff --git a/django/template/__init__.py b/django/template/__init__.py
index c316786..1fc2e7c 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -250,8 +250,9 @@ class Parser(object):
         for lib in builtins:
             self.add_library(lib)
 
-    def parse(self, parse_until=None):
-        if parse_until is None: parse_until = []
+    def parse(self, parse_until=None, parse_until_args_allowed=None):
+        parse_until = parse_until and list(parse_until) or []
+        parse_until_args_allowed = parse_until_args_allowed and list(parse_until_args_allowed) or []
         nodelist = self.create_nodelist()
         while self.tokens:
             token = self.next_token()
@@ -268,16 +269,23 @@ class Parser(object):
                     # put token back on token list so calling code knows why it terminated
                     self.prepend_token(token)
                     return nodelist
+
                 try:
                     command = token.contents.split()[0]
                 except IndexError:
                     self.empty_block_tag(token)
+
+                if command in parse_until_args_allowed:
+                    # put token back on token list so calling code knows why it terminated
+                    self.prepend_token(token)
+                    return nodelist
+
                 # execute callback function for this tag and append resulting node
                 self.enter_command(command, token)
                 try:
                     compile_func = self.tags[command]
                 except KeyError:
-                    self.invalid_block_tag(token, command, parse_until)
+                    self.invalid_block_tag(token, command, parse_until_args_allowed + parse_until)
                 try:
                     compiled_result = compile_func(self, token)
                 except TemplateSyntaxError, e:
@@ -285,8 +293,8 @@ class Parser(object):
                         raise
                 self.extend_nodelist(nodelist, compiled_result, token)
                 self.exit_command()
-        if parse_until:
-            self.unclosed_block_tag(parse_until)
+        if parse_until_args_allowed or parse_until:
+            self.unclosed_block_tag(parse_until_args_allowed + parse_until)
         return nodelist
 
     def skip_past(self, endtag):
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 1b07413..6043d36 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -235,29 +235,44 @@ class IfEqualNode(Node):
 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, condition_nodelists, else_nodelist):
+        self.condition_nodelists = condition_nodelists
+        self.else_nodelist = else_nodelist
 
     def __repr__(self):
         return "<If node>"
 
     def __iter__(self):
-        for node in self.nodelist_true:
-            yield node
-        for node in self.nodelist_false:
+        for condition, nodelist in self.condition_nodelists:
+            for node in nodelist:
+                yield node
+
+        for node in else_nodelist:
             yield node
 
+    def get_nodes_by_type(self, nodetype):
+        nodes = []
+        if isinstance(self, nodetype):
+            nodes.append(self)
+
+        for condition, nodelist in self.condition_nodelists:
+            nodes.extend(nodelist.get_nodes_by_type(nodetype))
+
+        nodes.extend(self.else_nodelist.get_nodes_by_type(nodetype))
+
+        return nodes
+
     def render(self, context):
-        try:
-            var = self.var.eval(context)
-        except VariableDoesNotExist:
-            var = None
+        for condition, nodelist in self.condition_nodelists:
+            try:
+                yes = condition.eval(context)
+            except VariableDoesNotExist:
+                yes = False
 
-        if var:
-            return self.nodelist_true.render(context)
-        else:
-            return self.nodelist_false.render(context)
+            if yes:
+                return nodelist.render(context)
+
+        return self.else_nodelist.render(context)
 
 class RegroupNode(Node):
     def __init__(self, target, expression, var_name):
@@ -788,6 +803,18 @@ def do_if(parser, token):
     As you can see, the ``if`` tag can take an option ``{% else %}`` clause
     that will be displayed if the test fails.
 
+    If you have multiple conditions to check against, you may wish to use
+    the ``elif`` tag::
+
+        {% if athlete_list %}
+            Number of athletes: {{ athlete_list|length }}
+        {% elif athletes_in_lockerroom %}
+            There are some athletes queued in the locker room, but they
+            should be out soon!
+        {% else %}
+            No athletes.
+        {% endif %}
+
     ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
     variables or to negate a given variable::
 
@@ -824,16 +851,37 @@ def do_if(parser, token):
 
     Operator precedence follows Python.
     """
-    bits = token.split_contents()[1:]
-    var = TemplateIfParser(parser, bits).parse()
-    nodelist_true = parser.parse(('else', 'endif'))
-    token = parser.next_token()
-    if token.contents == 'else':
-        nodelist_false = parser.parse(('endif',))
-        parser.delete_first_token()
-    else:
-        nodelist_false = NodeList()
-    return IfNode(var, nodelist_true, nodelist_false)
+    # The condition nodelist is constructed of:
+    # [(<if_var>, <nodelist>),
+    #   <if_var>, <nodelist>])]
+    #
+    # So as soon as one of these conditions evaluates to True, the
+    # accompanying nodelist is evaluated.
+    condition_nodelists = []
+    else_nodelist = None
+    all_parsed = False
+
+    while not all_parsed:
+        bits = token.split_contents()[1:]
+        var = TemplateIfParser(parser, bits).parse()
+        nodelist = parser.parse(('else', 'endif'), ('elif',))
+        condition_nodelists.append((var, nodelist))
+
+        token = parser.next_token()
+        command = token.contents.split()[0]
+        if command == 'elif':
+            pass
+        elif command == 'else':
+            else_nodelist = parser.parse(('endif',))
+            parser.delete_first_token()
+            all_parsed = True
+        elif command == 'endif':
+            all_parsed = True
+
+    if not else_nodelist:
+        else_nodelist = NodeList()
+
+    return IfNode(condition_nodelists, else_nodelist)
 do_if = register.tag("if", do_if)
 
 #@register.tag
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index a20ab17..969ff49 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -325,6 +325,20 @@ 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.
 
+.. versionadded:: 1.2
+
+If you have multiple conditions to check against, you may wish to use
+the ``elif`` tag::
+
+    {% if athlete_list %}
+        Number of athletes: {{ athlete_list|length }}
+    {% elif athletes_in_lockerroom %}
+        There are some athletes queued in the locker room, but they
+        should be out soon!
+    {% else %}
+        No athletes.
+    {% endif %}
+
 Boolean operators
 ^^^^^^^^^^^^^^^^^
 
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 9e2d175..e721aab 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -316,7 +316,7 @@ class Templates(unittest.TestCase):
         try:
             t = Template("{% if 1 %}lala{% endblock %}{% endif %}")
         except TemplateSyntaxError, e:
-            self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'")
+            self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'elif', 'else' or 'endif'")
 
     def test_templates(self):
         template_tests = self.get_template_tests()
@@ -711,6 +711,13 @@ 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{% else %}nothing{%endif%}",
+                         {'foo': True}, "foo"),
+            'if-tag05': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
+                         {'bar': True}, "bar"),
+            'if-tag06': ("{% if foo %}foo{% elif bar %}bar{% 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"),
