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}, ""),