Fixed #15570 -- Corrected a flaw in the design of the silent flag on {% cycle %}. Thanks to Brian Neal for the report, and to Andrew and Jannis for the design consult.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15773 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2011-03-08 13:43:53 +00:00
parent 32adde7fc9
commit c260c533e1
3 changed files with 46 additions and 13 deletions

View File

@ -111,12 +111,12 @@ class CycleNode(Node):
if self not in context.render_context: if self not in context.render_context:
# First time the node is rendered in template # First time the node is rendered in template
context.render_context[self] = itertools_cycle(self.cyclevars) context.render_context[self] = itertools_cycle(self.cyclevars)
if self.silent:
return ''
cycle_iter = context.render_context[self] cycle_iter = context.render_context[self]
value = cycle_iter.next().resolve(context) value = cycle_iter.next().resolve(context)
if self.variable_name: if self.variable_name:
context[self.variable_name] = value context[self.variable_name] = value
if self.silent:
return ''
return value return value
class DebugNode(Node): class DebugNode(Node):

View File

@ -102,11 +102,31 @@ outside of a loop. To do this, just give the ``{% cycle %}`` tag a name, using
{% cycle 'row1' 'row2' as rowcolors %} {% cycle 'row1' 'row2' as rowcolors %}
From then on, you can insert the current value of the cycle wherever you'd like From then on, you can insert the current value of the cycle wherever
in your template:: you'd like in your template by referencing the cycle name as a context
variable. If you want to move the cycle onto the next value, you use
the cycle tag again, using the name of the variable. So, the following
template::
<tr class="{% cycle rowcolors %}">...</tr> <tr>
<tr class="{% cycle rowcolors %}">...</tr> <td class="{% cycle 'row1' 'row2' as rowcolors %}">...</td>
<td class="{{ rowcolors }}">...</td>
</tr>
<tr>
<td class="{% cycle rowcolors %}">...</td>
<td class="{{ rowcolors }}">...</td>
</tr>
would output::
<tr>
<td class="row1">...</td>
<td class="row1">...</td>
</tr>
<tr>
<td class="row2">...</td>
<td class="row2">...</td>
</tr>
You can use any number of values in a ``{% cycle %}`` tag, separated by spaces. You can use any number of values in a ``{% cycle %}`` tag, separated by spaces.
Values enclosed in single (``'``) or double quotes (``"``) are treated as Values enclosed in single (``'``) or double quotes (``"``) are treated as
@ -144,16 +164,25 @@ use the value in a nested loop or an included template. If you want to
just declare the cycle, but not output the first value, you can add a just declare the cycle, but not output the first value, you can add a
``silent`` keyword as the last keyword in the tag. For example:: ``silent`` keyword as the last keyword in the tag. For example::
{% cycle 'row1' 'row2' as rowcolors silent %}
{% for obj in some_list %} {% for obj in some_list %}
<tr class="{% cycle rowcolors %}">{{ obj }}</tr> {% cycle 'row1' 'row2' as rowcolors silent %}
<tr class="{{ rowcolors }}">{% include "subtemplate.html " %}</tr>
{% endfor %} {% endfor %}
This will output a list of ``<tr>`` elements with ``class`` This will output a list of ``<tr>`` elements with ``class``
alternating between ``row1`` and ``row2``. If the ``silent`` keyword alternating between ``row1`` and ``row2``; the subtemplate will have
were to be omitted, ``row1`` would be emitted as normal text, outside access to ``rowcolors`` in it's context that matches the class of the
the list of ``<tr>`` elements, and the first ``<tr>`` would have a ``<tr>`` that encloses it. If the ``silent`` keyword were to be
class of ``row2``. omitted, ``row1`` would be emitted as normal text, outside the
``<tr>`` element.
When the silent keyword is used on a cycle definition, the silence
automatically applies to all subsequent uses of the cycle tag. In,
the following template would output *nothing*, even though the second
call to ``{% cycle %}`` doesn't specify silent::
{% cycle 'row1' 'row2' as rowcolors silent %}
{% cycle rowcolors %}
.. templatetag:: debug .. templatetag:: debug

View File

@ -735,11 +735,15 @@ class Templates(unittest.TestCase):
'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'), 'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'),
'cycle15': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'), 'cycle15': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'),
'cycle16': ("{% cycle one|lower two as foo %}{% cycle foo %}", {'one': 'A','two': '2'}, 'a2'), 'cycle16': ("{% cycle one|lower two as foo %}{% cycle foo %}", {'one': 'A','two': '2'}, 'a2'),
'cycle17': ("{% cycle 'a' 'b' 'c' as abc silent %}{% cycle abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, "abca"), 'cycle17': ("{% cycle 'a' 'b' 'c' as abc silent %}{% cycle abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, ""),
'cycle18': ("{% cycle 'a' 'b' 'c' as foo invalid_flag %}", {}, template.TemplateSyntaxError), 'cycle18': ("{% cycle 'a' 'b' 'c' as foo invalid_flag %}", {}, template.TemplateSyntaxError),
'cycle19': ("{% cycle 'a' 'b' as silent %}{% cycle silent %}", {}, "ab"), 'cycle19': ("{% cycle 'a' 'b' as silent %}{% cycle silent %}", {}, "ab"),
'cycle20': ("{% cycle one two as foo %} &amp; {% cycle foo %}", {'one' : 'A & B', 'two' : 'C & D'}, "A & B &amp; C & D"), 'cycle20': ("{% cycle one two as foo %} &amp; {% cycle foo %}", {'one' : 'A & B', 'two' : 'C & D'}, "A & B &amp; C & D"),
'cycle21': ("{% filter force_escape %}{% cycle one two as foo %} & {% cycle foo %}{% endfilter %}", {'one' : 'A & B', 'two' : 'C & D'}, "A &amp; B &amp; C &amp; D"), 'cycle21': ("{% filter force_escape %}{% cycle one two as foo %} & {% cycle foo %}{% endfilter %}", {'one' : 'A & B', 'two' : 'C & D'}, "A &amp; B &amp; C &amp; D"),
'cycle22': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{{ x }}{% endfor %}", {'values': [1,2,3,4]}, "1234"),
'cycle23': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{{ abc }}{{ x }}{% endfor %}", {'values': [1,2,3,4]}, "a1b2c3a4"),
'included-cycle': ('{{ abc }}', {'abc': 'xxx'}, 'xxx'),
'cycle24': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{% include 'included-cycle' %}{% endfor %}", {'values': [1,2,3,4]}, "abca"),
### EXCEPTIONS ############################################################ ### EXCEPTIONS ############################################################