Ticket #3100: fix3100.patch

File fix3100.patch, 9.0 KB (added by Matthias Kestenholz, 14 years ago)
  • django/template/__init__.py

    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 b class Parser(object):  
    250250        for lib in builtins:
    251251            self.add_library(lib)
    252252
    253     def parse(self, parse_until=None):
    254         if parse_until is None: parse_until = []
     253    def parse(self, parse_until=None, parse_until_args_allowed=None):
     254        parse_until = parse_until and list(parse_until) or []
     255        parse_until_args_allowed = parse_until_args_allowed and list(parse_until_args_allowed) or []
    255256        nodelist = self.create_nodelist()
    256257        while self.tokens:
    257258            token = self.next_token()
    class Parser(object):  
    268269                    # put token back on token list so calling code knows why it terminated
    269270                    self.prepend_token(token)
    270271                    return nodelist
     272
    271273                try:
    272274                    command = token.contents.split()[0]
    273275                except IndexError:
    274276                    self.empty_block_tag(token)
     277
     278                if command in parse_until_args_allowed:
     279                    # put token back on token list so calling code knows why it terminated
     280                    self.prepend_token(token)
     281                    return nodelist
     282
    275283                # execute callback function for this tag and append resulting node
    276284                self.enter_command(command, token)
    277285                try:
    278286                    compile_func = self.tags[command]
    279287                except KeyError:
    280                     self.invalid_block_tag(token, command, parse_until)
     288                    self.invalid_block_tag(token, command, parse_until_args_allowed + parse_until)
    281289                try:
    282290                    compiled_result = compile_func(self, token)
    283291                except TemplateSyntaxError, e:
    class Parser(object):  
    285293                        raise
    286294                self.extend_nodelist(nodelist, compiled_result, token)
    287295                self.exit_command()
    288         if parse_until:
    289             self.unclosed_block_tag(parse_until)
     296        if parse_until_args_allowed or parse_until:
     297            self.unclosed_block_tag(parse_until_args_allowed + parse_until)
    290298        return nodelist
    291299
    292300    def skip_past(self, endtag):
  • django/template/defaulttags.py

    diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
    index 1b07413..6043d36 100644
    a b class IfEqualNode(Node):  
    235235class IfNode(Node):
    236236    child_nodelists = ('nodelist_true', 'nodelist_false')
    237237
    238     def __init__(self, var, nodelist_true, nodelist_false=None):
    239         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
    240         self.var = var
     238    def __init__(self, condition_nodelists, else_nodelist):
     239        self.condition_nodelists = condition_nodelists
     240        self.else_nodelist = else_nodelist
    241241
    242242    def __repr__(self):
    243243        return "<If node>"
    244244
    245245    def __iter__(self):
    246         for node in self.nodelist_true:
    247             yield node
    248         for node in self.nodelist_false:
     246        for condition, nodelist in self.condition_nodelists:
     247            for node in nodelist:
     248                yield node
     249
     250        for node in else_nodelist:
    249251            yield node
    250252
     253    def get_nodes_by_type(self, nodetype):
     254        nodes = []
     255        if isinstance(self, nodetype):
     256            nodes.append(self)
     257
     258        for condition, nodelist in self.condition_nodelists:
     259            nodes.extend(nodelist.get_nodes_by_type(nodetype))
     260
     261        nodes.extend(self.else_nodelist.get_nodes_by_type(nodetype))
     262
     263        return nodes
     264
    251265    def render(self, context):
    252         try:
    253             var = self.var.eval(context)
    254         except VariableDoesNotExist:
    255             var = None
     266        for condition, nodelist in self.condition_nodelists:
     267            try:
     268                yes = condition.eval(context)
     269            except VariableDoesNotExist:
     270                yes = False
    256271
    257         if var:
    258             return self.nodelist_true.render(context)
    259         else:
    260             return self.nodelist_false.render(context)
     272            if yes:
     273                return nodelist.render(context)
     274
     275        return self.else_nodelist.render(context)
    261276
    262277class RegroupNode(Node):
    263278    def __init__(self, target, expression, var_name):
    def do_if(parser, token):  
    788803    As you can see, the ``if`` tag can take an option ``{% else %}`` clause
    789804    that will be displayed if the test fails.
    790805
     806    If you have multiple conditions to check against, you may wish to use
     807    the ``elif`` tag::
     808
     809        {% if athlete_list %}
     810            Number of athletes: {{ athlete_list|length }}
     811        {% elif athletes_in_lockerroom %}
     812            There are some athletes queued in the locker room, but they
     813            should be out soon!
     814        {% else %}
     815            No athletes.
     816        {% endif %}
     817
    791818    ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
    792819    variables or to negate a given variable::
    793820
    def do_if(parser, token):  
    824851
    825852    Operator precedence follows Python.
    826853    """
    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)
     854    # The condition nodelist is constructed of:
     855    # [(<if_var>, <nodelist>),
     856    #   <if_var>, <nodelist>])]
     857    #
     858    # So as soon as one of these conditions evaluates to True, the
     859    # accompanying nodelist is evaluated.
     860    condition_nodelists = []
     861    else_nodelist = None
     862    all_parsed = False
     863
     864    while not all_parsed:
     865        bits = token.split_contents()[1:]
     866        var = TemplateIfParser(parser, bits).parse()
     867        nodelist = parser.parse(('else', 'endif'), ('elif',))
     868        condition_nodelists.append((var, nodelist))
     869
     870        token = parser.next_token()
     871        command = token.contents.split()[0]
     872        if command == 'elif':
     873            pass
     874        elif command == 'else':
     875            else_nodelist = parser.parse(('endif',))
     876            parser.delete_first_token()
     877            all_parsed = True
     878        elif command == 'endif':
     879            all_parsed = True
     880
     881    if not else_nodelist:
     882        else_nodelist = NodeList()
     883
     884    return IfNode(condition_nodelists, else_nodelist)
    837885do_if = register.tag("if", do_if)
    838886
    839887#@register.tag
  • docs/ref/templates/builtins.txt

    diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
    index a20ab17..969ff49 100644
    a b displayed by the ``{{ athlete_list|length }}`` variable.  
    325325As you can see, the ``if`` tag can take an optional ``{% else %}`` clause that
    326326will be displayed if the test fails.
    327327
     328.. versionadded:: 1.2
     329
     330If you have multiple conditions to check against, you may wish to use
     331the ``elif`` tag::
     332
     333    {% if athlete_list %}
     334        Number of athletes: {{ athlete_list|length }}
     335    {% elif athletes_in_lockerroom %}
     336        There are some athletes queued in the locker room, but they
     337        should be out soon!
     338    {% else %}
     339        No athletes.
     340    {% endif %}
     341
    328342Boolean operators
    329343^^^^^^^^^^^^^^^^^
    330344
  • tests/regressiontests/templates/tests.py

    diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
    index 9e2d175..e721aab 100644
    a b class Templates(unittest.TestCase):  
    316316        try:
    317317            t = Template("{% if 1 %}lala{% endblock %}{% endif %}")
    318318        except TemplateSyntaxError, e:
    319             self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'")
     319            self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'elif', 'else' or 'endif'")
    320320
    321321    def test_templates(self):
    322322        template_tests = self.get_template_tests()
    class Templates(unittest.TestCase):  
    711711            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
    712712            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),
    713713
     714            'if-tag04': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     715                         {'foo': True}, "foo"),
     716            'if-tag05': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     717                         {'bar': True}, "bar"),
     718            'if-tag06': ("{% if foo %}foo{% elif bar %}bar{% else %}nothing{%endif%}",
     719                         {}, "nothing"),
     720
    714721            # Filters
    715722            'if-tag-filter01': ("{% if foo|length == 5 %}yes{% else %}no{% endif %}", {'foo': 'abcde'}, "yes"),
    716723            'if-tag-filter02': ("{% if foo|upper == 'ABC' %}yes{% else %}no{% endif %}", {}, "no"),
Back to Top