diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 01c43ee86fd..587d5d9fff9 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -157,8 +157,8 @@ class ForNode(Node): return nodelist.render(context) class IfChangedNode(Node): - def __init__(self, nodelist, *varlist): - self.nodelist = nodelist + def __init__(self, nodelist_true, nodelist_false, *varlist): + self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self._last_seen = None self._varlist = map(Variable, varlist) self._id = str(id(self)) @@ -173,20 +173,21 @@ class IfChangedNode(Node): # like an OR evaluation of the multiple variables. compare_to = [var.resolve(context) for var in self._varlist] else: - compare_to = self.nodelist.render(context) + compare_to = self.nodelist_true.render(context) except VariableDoesNotExist: compare_to = None - if compare_to != self._last_seen: + if compare_to != self._last_seen: firstloop = (self._last_seen == None) self._last_seen = compare_to context.push() context['ifchanged'] = {'firstloop': firstloop} - content = self.nodelist.render(context) + content = self.nodelist_true.render(context) context.pop() return content - else: - return '' + elif self.nodelist_false: + return self.nodelist_false.render(context) + return '' class IfEqualNode(Node): def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): @@ -803,9 +804,14 @@ def ifchanged(parser, token): {% endfor %} """ bits = token.contents.split() - nodelist = parser.parse(('endifchanged',)) - parser.delete_first_token() - return IfChangedNode(nodelist, *bits[1:]) + nodelist_true = parser.parse(('else', 'endifchanged')) + token = parser.next_token() + if token.contents == 'else': + nodelist_false = parser.parse(('endifchanged',)) + parser.delete_first_token() + else: + nodelist_false = NodeList() + return IfChangedNode(nodelist_true, nodelist_false, *bits[1:]) ifchanged = register.tag(ifchanged) #@register.tag diff --git a/docs/templates.txt b/docs/templates.txt index d3ec139f063..4bf8214a2a5 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -828,6 +828,19 @@ The 'ifchanged' block tag is used within a loop. It has two possible uses. {% endifchanged %} {% endfor %} +The ``ifchanged`` tag also takes an optional ``{% else %}`` clause that will +be displayed if the value has not changed:: + + {% for match in matches %} +
{{ match }}
+ {% endfor %} + ifequal ~~~~~~~ diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 186b8aacb55..e3a7091212f 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -565,6 +565,14 @@ class Templates(unittest.TestCase): # ifchanged for the day. 'ifchanged-param04': ('{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'), + # Test the else clause of ifchanged. + 'ifchanged-else01': ('{% for id in ids %}{{ id }}{% ifchanged id %}-first{% else %}-other{% endifchanged %},{% endfor %}', {'ids': [1,1,2,2,2,3]}, '1-first,1-other,2-first,2-other,2-other,3-first,'), + + 'ifchanged-else02': ('{% for id in ids %}{{ id }}-{% ifchanged id %}{% cycle red,blue %}{% else %}grey{% endifchanged %},{% endfor %}', {'ids': [1,1,2,2,2,3]}, '1-red,1-grey,2-blue,2-grey,2-grey,3-red,'), + 'ifchanged-else03': ('{% for id in ids %}{{ id }}{% ifchanged id %}-{% cycle red,blue %}{% else %}{% endifchanged %},{% endfor %}', {'ids': [1,1,2,2,2,3]}, '1-red,1,2-blue,2,2,3-red,'), + + 'ifchanged-else04': ('{% for id in ids %}{% ifchanged %}***{{ id }}*{% else %}...{% endifchanged %}{{ forloop.counter }}{% endfor %}', {'ids': [1,1,2,2,2,3,4]}, '***1*1...2***2*3...4...5***3*6***4*7'), + ### IFEQUAL TAG ########################################################### 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), 'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"), @@ -712,7 +720,7 @@ class Templates(unittest.TestCase): # Inheritance from a template that doesn't have any blocks 'inheritance27': ("{% extends 'inheritance26' %}", {}, 'no tags'), - + ### I18N ################################################################## # {% spaceless %} tag @@ -893,16 +901,16 @@ class Templates(unittest.TestCase): 'cache07': ('{% load cache %}{% cache 2 test foo %}cache07{% endcache %}', {'foo': 1}, 'cache05'), # Allow first argument to be a variable. - 'cache08': ('{% load cache %}{% cache time test foo %}cache08{% endcache %}', {'foo': 2, 'time': 2}, 'cache06'), - 'cache09': ('{% load cache %}{% cache time test foo %}cache09{% endcache %}', {'foo': 3, 'time': -1}, 'cache09'), - 'cache10': ('{% load cache %}{% cache time test foo %}cache10{% endcache %}', {'foo': 3, 'time': -1}, 'cache10'), + 'cache08': ('{% load cache %}{% cache time test foo %}cache08{% endcache %}', {'foo': 2, 'time': 2}, 'cache06'), + 'cache09': ('{% load cache %}{% cache time test foo %}cache09{% endcache %}', {'foo': 3, 'time': -1}, 'cache09'), + 'cache10': ('{% load cache %}{% cache time test foo %}cache10{% endcache %}', {'foo': 3, 'time': -1}, 'cache10'), # Raise exception if we don't have at least 2 args, first one integer. 'cache11': ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError), 'cache12': ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError), 'cache13': ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError), - 'cache14': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': 'fail'}, template.TemplateSyntaxError), - 'cache15': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': []}, template.TemplateSyntaxError), + 'cache14': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': 'fail'}, template.TemplateSyntaxError), + 'cache15': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': []}, template.TemplateSyntaxError), ### AUTOESCAPE TAG ############################################## 'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),