Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17187 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 19cbdf8c8f6f5da5687cfec659841176b6af7d67 1 parent 959f78b
@aaugustin aaugustin authored
View
77 django/template/defaulttags.py
@@ -250,31 +250,37 @@ def render(self, context):
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:
- yield node
+ 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):
- try:
- var = self.var.eval(context)
- except VariableDoesNotExist:
- var = None
+ for condition, nodelist in self.conditions_nodelists:
- if var:
- return self.nodelist_true.render(context)
- else:
- return self.nodelist_false.render(context)
+ if condition is not None: # if / elif clause
+ try:
+ match = condition.eval(context)
+ except VariableDoesNotExist:
+ match = None
+ else: # else clause
+ match = True
+
+ 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):
View
11 docs/ref/templates/builtins.txt
@@ -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
^^^^^^^^^^^^^^^^^
View
2  docs/releases/1.4.txt
@@ -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
View
13 tests/regressiontests/templates/tests.py
@@ -394,7 +394,7 @@ def test_invalid_block_suggestion(self):
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 @@ def get_template_tests(self):
'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"),

0 comments on commit 19cbdf8

Please sign in to comment.
Something went wrong with that request. Please try again.