diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 6144267c1a..c2e29e5342 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -124,17 +124,27 @@ class ForNode(Node): return nodelist.render(context) class IfChangedNode(Node): - def __init__(self, nodelist): + def __init__(self, nodelist, *varlist): self.nodelist = nodelist self._last_seen = None + self._varlist = varlist def render(self, context): if context.has_key('forloop') and context['forloop']['first']: self._last_seen = None - content = self.nodelist.render(context) - if content != self._last_seen: + try: + if self._varlist: + # Consider multiple parameters. + # This automatically behaves like a OR evaluation of the multiple variables. + compare_to = [resolve_variable(var, context) for var in self._varlist] + else: + compare_to = self.nodelist.render(context) + except VariableDoesNotExist: + compare_to = None + + if compare_to != self._last_seen: firstloop = (self._last_seen == None) - self._last_seen = content + self._last_seen = compare_to context.push() context['ifchanged'] = {'firstloop': firstloop} content = self.nodelist.render(context) @@ -634,23 +644,34 @@ def ifchanged(parser, token): """ Check if a value has changed from the last iteration of a loop. - The 'ifchanged' block tag is used within a loop. It checks its own rendered - contents against its previous state and only displays its content if the - value has changed:: + The 'ifchanged' block tag is used within a loop. It has two possible uses. -

Archive for {{ year }}

+ 1. Checks its own rendered contents against its previous state and only + displays the content if it has changed. For example, this displays a list of + days, only displaying the month if it changes:: - {% for date in days %} - {% ifchanged %}

{{ date|date:"F" }}

{% endifchanged %} - {{ date|date:"j" }} - {% endfor %} +

Archive for {{ year }}

+ + {% for date in days %} + {% ifchanged %}

{{ date|date:"F" }}

{% endifchanged %} + {{ date|date:"j" }} + {% endfor %} + + 2. If given a variable, check if that variable has changed. For example, the + following shows the date every time it changes, but only shows the hour if both + the hour and the date has changed:: + + {% for date in days %} + {% ifchanged date.date %} {{date.date}} {% endifchanged %} + {% ifchanged date.hour date.date %} + {{date.hour}} + {% endifchanged %} + {% endfor %} """ bits = token.contents.split() - if len(bits) != 1: - raise TemplateSyntaxError, "'ifchanged' tag takes no arguments" nodelist = parser.parse(('endifchanged',)) parser.delete_first_token() - return IfChangedNode(nodelist) + return IfChangedNode(nodelist, *bits[1:]) ifchanged = register.tag(ifchanged) #@register.tag diff --git a/docs/templates.txt b/docs/templates.txt index 92d4b53660..cb06fa27d9 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -525,16 +525,29 @@ ifchanged Check if a value has changed from the last iteration of a loop. -The ``ifchanged`` block tag is used within a loop. It checks its own rendered -contents against its previous state and only displays its content if the value -has changed:: +The 'ifchanged' block tag is used within a loop. It has two possible uses. -

Archive for {{ year }}

+1. Checks its own rendered contents against its previous state and only + displays the content if it has changed. For example, this displays a list of + days, only displaying the month if it changes:: - {% for day in days %} - {% ifchanged %}

{{ day|date:"F" }}

{% endifchanged %} - {{ day|date:"j" }} - {% endfor %} +

Archive for {{ year }}

+ + {% for date in days %} + {% ifchanged %}

{{ date|date:"F" }}

{% endifchanged %} + {{ date|date:"j" }} + {% endfor %} + +2. If given a variable, check if that variable has changed. For example, the + following shows the date every time it changes, but only shows the hour if both + the hour and the date has changed:: + + {% for date in days %} + {% ifchanged date.date %} {{date.date}} {% endifchanged %} + {% ifchanged date.hour date.date %} + {{date.hour}} + {% endifchanged %} + {% endfor %} ifequal ~~~~~~~ diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index bcb9c66254..3c31bb0604 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -328,6 +328,21 @@ class Templates(unittest.TestCase): 'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'), 'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'), 'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'), + + # Test one parameter given to ifchanged. + 'ifchanged-param01': ('{% for n in num %}{% ifchanged n %}..{% endifchanged %}{{ n }}{% endfor %}', { 'num': (1,2,3) }, '..1..2..3'), + 'ifchanged-param02': ('{% for n in num %}{% for x in numx %}{% ifchanged n %}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}', { 'num': (1,2,3), 'numx': (5,6,7) }, '..567..567..567'), + + # Test multiple parameters to ifchanged. + 'ifchanged-param03': ('{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1,1,2), 'numx': (5,6,6) }, '156156256'), + + # Test a date+hour like construct, where the hour of the last day + # is the same but the date had changed, so print the hour anyway. + 'ifchanged-param04': ('{% for d in days %}{% ifchanged %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'), + + # Logically the same as above, just written with explicit + # 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'), ### IFEQUAL TAG ########################################################### 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),