Ticket #3100: django_elif.diff

File django_elif.diff, 8.8 KB (added by cwebber, 14 years ago)

Django {% elif %} tag support (now with docs in the same patch)

  • django/template/__init__.py

    diff --git a/django/template/__init__.py b/django/template/__init__.py
    index 4c386be..881e16a 100644
    a b class Parser(object):  
    275275                var_node = self.create_variable_node(filter_expression)
    276276                self.extend_nodelist(nodelist, var_node,token)
    277277            elif token.token_type == TOKEN_BLOCK:
    278                 if token.contents in parse_until:
    279                     # put token back on token list so calling code knows why it terminated
    280                     self.prepend_token(token)
    281                     return nodelist
    282278                try:
    283279                    command = token.contents.split()[0]
    284280                except IndexError:
    285281                    self.empty_block_tag(token)
     282                if command in parse_until:
     283                    # put token back on token list so calling code knows why it terminated
     284                    self.prepend_token(token)
     285                    return nodelist
    286286                # execute callback function for this tag and append resulting node
    287287                self.enter_command(command, token)
    288288                try:
  • django/template/defaulttags.py

    diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
    index 2ccfc6a..28b3385 100644
    a b class IfEqualNode(Node):  
    231231        return self.nodelist_false.render(context)
    232232
    233233class IfNode(Node):
    234     def __init__(self, var, nodelist_true, nodelist_false=None):
    235         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
    236         self.var = var
     234    def __init__(self, condition_nodelists, else_nodelist):
     235        self.condition_nodelists = condition_nodelists
     236        self.else_nodelist = else_nodelist
    237237
    238238    def __repr__(self):
    239239        return "<If node>"
    240240
    241241    def __iter__(self):
    242         for node in self.nodelist_true:
    243             yield node
    244         for node in self.nodelist_false:
     242        for condition, nodelist in self.condition_nodelists:
     243            for node in nodelist:
     244                yield node
     245
     246        for node in else_nodelist:
    245247            yield node
    246248
    247249    def get_nodes_by_type(self, nodetype):
    248250        nodes = []
    249251        if isinstance(self, nodetype):
    250252            nodes.append(self)
    251         nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
    252         nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
     253
     254        for condition, nodelist in self.condition_nodelists:
     255            nodes.extend(nodelist.get_nodes_by_type(nodetype))
     256
     257        nodes.extend(self.else_nodelist.get_nodes_by_type(nodetype))
     258
    253259        return nodes
    254260
    255261    def render(self, context):
    256         if self.var.eval(context):
    257             return self.nodelist_true.render(context)
    258         else:
    259             return self.nodelist_false.render(context)
     262        for condition, nodelist in self.condition_nodelists:
     263            if condition.eval(context):
     264                return nodelist.render(context)
     265
     266        return self.else_nodelist.render(context)
    260267
    261268class RegroupNode(Node):
    262269    def __init__(self, target, expression, var_name):
    def do_if(parser, token):  
    788795    As you can see, the ``if`` tag can take an option ``{% else %}`` clause
    789796    that will be displayed if the test fails.
    790797
     798    If you have multiple conditions to check against, you may wish to use
     799    the ``elif`` tag::
     800   
     801        {% if athlete_list %}
     802            Number of athletes: {{ athlete_list|length }}
     803        {% elif athletes_in_lockerroom %}
     804            There are some athletes queued in the locker room, but they
     805            should be out soon!
     806        {% else %}
     807            No athletes.
     808        {% endif %}
     809
    791810    ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
    792811    variables or to negate a given variable::
    793812
    def do_if(parser, token):  
    824843
    825844    Operator precedence follows Python.
    826845    """
    827     bits = token.split_contents()[1:]
    828     var = TemplateIfParser(parser, bits).parse()
    829     nodelist_true = parser.parse(('else', 'endif'))
    830     token = parser.next_token()
    831     if token.contents == 'else':
    832         nodelist_false = parser.parse(('endif',))
    833         parser.delete_first_token()
    834     else:
    835         nodelist_false = NodeList()
    836     return IfNode(var, nodelist_true, nodelist_false)
     846    # The condition nodelist is constructed of:
     847    # [(<if_var>, <nodelist>),
     848    #   <if_var>, <nodelist>])]
     849    #
     850    # So as soon as one of these conditions evaluates to True, the
     851    # accompanying nodelist is evaluated.
     852    condition_nodelists = []
     853    else_nodelist = None
     854    all_parsed = False
     855
     856    while not all_parsed:
     857        bits = token.split_contents()[1:]
     858        var = TemplateIfParser(parser, bits).parse()
     859        nodelist = parser.parse(('elif', 'else', 'endif'))
     860        condition_nodelists.append((var, nodelist))
     861
     862        token = parser.next_token()
     863        command = token.contents.split()[0]
     864        if command == 'elif':
     865            pass
     866        elif command == 'else':
     867            else_nodelist = parser.parse(('endif',))
     868            parser.delete_first_token()
     869            all_parsed = True
     870        elif command == 'endif':
     871            all_parsed = True
     872
     873    if not else_nodelist:
     874        else_nodelist = NodeList()
     875
     876    return IfNode(condition_nodelists, else_nodelist)
    837877do_if = register.tag("if", do_if)
    838878
    839879#@register.tag
  • docs/ref/templates/builtins.txt

    diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
    index 51ef03c..16f1820 100644
    a b displayed by the ``{{ athlete_list|length }}`` variable.  
    313313As you can see, the ``if`` tag can take an optional ``{% else %}`` clause that
    314314will be displayed if the test fails.
    315315
     316.. versionadded:: 1.2
     317
     318If you have multiple conditions to check against, you may wish to use
     319the ``elif`` tag::
     320
     321    {% if athlete_list %}
     322        Number of athletes: {{ athlete_list|length }}
     323    {% elif athletes_in_lockerroom %}
     324        There are some athletes queued in the locker room, but they
     325        should be out soon!
     326    {% else %}
     327        No athletes.
     328    {% endif %}
     329
    316330Boolean operators
    317331^^^^^^^^^^^^^^^^^
    318332
  • tests/regressiontests/templates/tests.py

    diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
    index 2946208..99aacff 100644
    a b class Templates(unittest.TestCase):  
    542542            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
    543543            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
    544544
     545            'if-tag04': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     546                         {'foo': True}, "foo"),
     547            'if-tag05': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     548                         {'bar': True}, "bar"),
     549            'if-tag06': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     550                         {}, "nothing"),
     551
    545552            # Filters
    546553            'if-tag-filter01': ("{% if foo|length == 5 %}yes{% else %}no{% endif %}", {'foo': 'abcde'}, "yes"),
    547554            'if-tag-filter02': ("{% if foo|upper == 'ABC' %}yes{% else %}no{% endif %}", {}, "no"),
    class Templates(unittest.TestCase):  
    741748            'namedendblocks01': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock first %}3", {}, '1_2_3'),
    742749
    743750            # Unbalanced blocks
    744             'namedendblocks02': ("1{% block first %}_{% block second %}2{% endblock first %}_{% endblock second %}3", {}, template.TemplateSyntaxError),
    745             'namedendblocks03': ("1{% block first %}_{% block second %}2{% endblock %}_{% endblock second %}3", {}, template.TemplateSyntaxError),
    746             'namedendblocks04': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock third %}3", {}, template.TemplateSyntaxError),
    747             'namedendblocks05': ("1{% block first %}_{% block second %}2{% endblock first %}", {}, template.TemplateSyntaxError),
     751            'namedendblocks02': ("1{% block first %}_{% block second %}2{% endblock first %}", {}, template.TemplateSyntaxError),
    748752
    749753            # Mixed named and unnamed endblocks
    750             'namedendblocks06': ("1{% block first %}_{% block second %}2{% endblock %}_{% endblock first %}3", {}, '1_2_3'),
    751             'namedendblocks07': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock %}3", {}, '1_2_3'),
     754            'namedendblocks03': ("1{% block first %}_{% block second %}2{% endblock %}_{% endblock first %}3", {}, '1_2_3'),
     755            'namedendblocks04': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock %}3", {}, '1_2_3'),
    752756
    753757            ### INHERITANCE ###########################################################
    754758
Back to Top