Ticket #3523: for_tag.5.patch
File for_tag.5.patch, 7.9 KB (added by , 17 years ago) |
---|
-
django/template/defaulttags.py
61 61 return '' 62 62 63 63 class ForNode(Node): 64 def __init__(self, loopvar , sequence, reversed, nodelist_loop):65 self.loopvar , self.sequence = loopvar, sequence64 def __init__(self, loopvars, sequence, reversed, nodelist_loop): 65 self.loopvars, self.sequence = loopvars, sequence 66 66 self.reversed = reversed 67 67 self.nodelist_loop = nodelist_loop 68 68 … … 72 72 else: 73 73 reversed = '' 74 74 return "<For Node: for %s in %s, tail_len: %d%s>" % \ 75 ( self.loopvar, self.sequence, len(self.nodelist_loop), reversed)75 (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed) 76 76 77 77 def __iter__(self): 78 78 for node in self.nodelist_loop: … … 107 107 for index in range(len(data)-1, -1, -1): 108 108 yield data[index] 109 109 values = reverse(values) 110 unpack = len(self.loopvars) > 1 110 111 for i, item in enumerate(values): 111 112 context['forloop'] = { 112 113 # shortcuts for current loop iteration number … … 120 121 'last': (i == len_values - 1), 121 122 'parentloop': parentloop, 122 123 } 123 context[self.loopvar] = item 124 if unpack: 125 # If multiple loop variables, unpack the item to them. 126 context.update(dict(zip(self.loopvars, item))) 127 else: 128 context[self.loopvars[0]] = item 124 129 for node in self.nodelist_loop: 125 130 nodelist.append(node.render(context)) 131 if unpack: 132 # The loop variables were pushed on to the context so pop them 133 # off again. This is necessary because the tag lets the length 134 # of loopvars differ to the length of each set of items and we 135 # don't want to leave any vars from this previous loop on the 136 # context. 137 context.pop() 126 138 context.pop() 127 139 return nodelist.render(context) 128 140 … … 486 498 nodelist = parser.parse(('endfilter',)) 487 499 parser.delete_first_token() 488 500 return FilterNode(filter_expr, nodelist) 489 filter = register.tag("filter", do_filter)501 do_filter = register.tag("filter", do_filter) 490 502 491 503 #@register.tag 492 504 def firstof(parser, token): … … 530 542 {% endfor %} 531 543 </ul> 532 544 533 You can alsoloop over a list in reverse by using545 You can loop over a list in reverse by using 534 546 ``{% for obj in list reversed %}``. 547 548 You can also unpack multiple values from a two-dimensional array:: 549 550 {% for key,value in dict.items %} 551 {{ key }}: {{ value }} 552 {% endfor %} 535 553 536 554 The for loop sets a number of variables available within the loop: 537 555 … … 552 570 553 571 """ 554 572 bits = token.contents.split() 555 if len(bits) == 5 and bits[4] != 'reversed': 556 raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents 557 if len(bits) not in (4, 5): 558 raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents 559 if bits[2] != 'in': 560 raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents 561 loopvar = bits[1] 562 sequence = parser.compile_filter(bits[3]) 563 reversed = (len(bits) == 5) 573 if len(bits) < 4: 574 raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents 575 576 reversed = bits[-1] == 'reversed' 577 in_index = reversed and -3 or -2 578 if bits[in_index] != 'in': 579 raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents 580 581 loopvars = ' '.join(bits[1:in_index]).replace(', ', ',').split(',') 582 for var in loopvars: 583 if not var or ' ' in var: 584 raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents 585 586 sequence = parser.compile_filter(bits[in_index+1]) 564 587 nodelist_loop = parser.parse(('endfor',)) 565 588 parser.delete_first_token() 566 return ForNode(loopvar , sequence, reversed, nodelist_loop)589 return ForNode(loopvars, sequence, reversed, nodelist_loop) 567 590 do_for = register.tag("for", do_for) 568 591 569 592 def do_ifequal(parser, token, negate): -
docs/templates.txt
444 444 ~~~ 445 445 446 446 Loop over each item in an array. For example, to display a list of athletes 447 given ``athlete_list``::447 provided in ``athlete_list``:: 448 448 449 449 <ul> 450 450 {% for athlete in athlete_list %} … … 452 452 {% endfor %} 453 453 </ul> 454 454 455 You can alsoloop over a list in reverse by using ``{% for obj in list reversed %}``.455 You can loop over a list in reverse by using ``{% for obj in list reversed %}``. 456 456 457 For advanced use, you can unpack multiple values from a list of fixed length 458 lists. For example, to display the keys and values of a Python dictionary:: 459 460 {% for key, value in dict.iteritems %} 461 {{ key }}: {{ value }} 462 {% endfor %} 463 457 464 The for loop sets a number of variables available within the loop: 458 465 459 466 ========================== ================================================ -
tests/regressiontests/templates/tests.py
289 289 'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"), 290 290 'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), 291 291 'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"), 292 'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 293 'for-tag-unpack02': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 294 'for-tag-unpack03': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 295 'for-tag-unpack04': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 296 'for-tag-unpack05': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError), 297 # Ensure that a single loopvar doesn't truncate the list in val. 298 'for-tag-unpack06': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"), 299 # Otherwise, silently truncate if the length of loopvars differs to the length of each set of items. 300 'for-tag-unpack07': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"), 301 'for-tag-unpack08': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, ("one:1,/two:2,/", "one:1,INVALID/two:2,INVALID/")), 302 'for-tag-unpack09': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")), 292 303 293 304 ### IF TAG ################################################################ 294 305 'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),