diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 1b07413530..687a74477f 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -53,13 +53,17 @@ class CsrfTokenNode(Node):
return u''
class CycleNode(Node):
- def __init__(self, cyclevars, variable_name=None):
+ def __init__(self, cyclevars, variable_name=None, silent=False):
self.cyclevars = cyclevars
self.variable_name = variable_name
+ self.silent = silent
def render(self, context):
if self not in context.render_context:
+ # First time the node is rendered in template
context.render_context[self] = itertools_cycle(self.cyclevars)
+ if self.silent:
+ return ''
cycle_iter = context.render_context[self]
value = cycle_iter.next().resolve(context)
if self.variable_name:
@@ -482,6 +486,17 @@ def cycle(parser, token):
You can use any number of values, separated by spaces. Commas can also
be used to separate values; if a comma is used, the cycle values are
interpreted as literal strings.
+
+ The optional flag "silent" can be used to prevent the cycle declaration
+ from returning any value::
+
+ {% cycle 'row1' 'row2' as rowcolors silent %}{# no value here #}
+ {% for o in some_list %}
+
{# first value will be "row1" #}
+ ...
+
+ {% endfor %}
+
"""
# Note: This returns the exact same node on each {% cycle name %} call;
@@ -513,10 +528,24 @@ def cycle(parser, token):
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes[name]
- if len(args) > 4 and args[-2] == 'as':
+ as_form = False
+
+ if len(args) > 4:
+ # {% cycle ... as foo [silent] %} case.
+ if args[-3] == "as":
+ if args[-1] != "silent":
+ raise TemplateSyntaxError("Only 'silent' flag is allowed after cycle's name, not '%s'." % args[-1])
+ as_form = True
+ silent = True
+ args = args[:-1]
+ elif args[-2] == "as":
+ as_form = True
+ silent = False
+
+ if as_form:
name = args[-1]
values = [parser.compile_filter(arg) for arg in args[1:-2]]
- node = CycleNode(values, name)
+ node = CycleNode(values, name, silent=silent)
if not hasattr(parser, '_namedCycleNodes'):
parser._namedCycleNodes = {}
parser._namedCycleNodes[name] = node
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 7bb4481904..5fdef71a5f 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -140,6 +140,26 @@ In this syntax, each value gets interpreted as a literal string, and there's no
way to specify variable values. Or literal commas. Or spaces. Did we mention
you shouldn't use this syntax in any new projects?
+.. versionadded:: 1.3
+
+By default, when you use the ``as`` keyword with the cycle tag, the
+usage of ``{% cycle %}`` that declares the cycle will itself output
+the first value in the cycle. This could be a problem if you want to
+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
+``silent`` keyword as the last keyword in the tag. For example::
+
+ {% cycle 'row1' 'row2' as rowcolors silent %}
+ {% for obj in some_list %}
+ {{ obj }}
+ {% endfor %}
+
+This will output a list of ```` elements with ``class``
+alternating between ``row1`` and ``row2``. If the ``silent`` keyword
+were to be omitted, ``row1`` would be emitted as normal text, outside
+the list of ``
`` elements, and the first ``
`` would have a
+class of ``row2``.
+
.. templatetag:: debug
debug
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 492d795117..2da6d48de7 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -646,6 +646,9 @@ class Templates(unittest.TestCase):
'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,'),
'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"),
+ 'cycle18': ("{% cycle 'a' 'b' 'c' as foo invalid_flag %}", {}, template.TemplateSyntaxError),
+ 'cycle19': ("{% cycle 'a' 'b' as silent %}{% cycle silent %}", {}, "ab"),
### EXCEPTIONS ############################################################