Fixed #2800: the ifchanged tag now can optionally take paramaters to be checked for changing (instead of always using the content). Thanks, Wolfram Kriesing.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4050 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jacob Kaplan-Moss 2006-11-07 05:36:51 +00:00
parent a14dba5eed
commit b1b4e8e7c4
3 changed files with 72 additions and 23 deletions

View File

@ -124,17 +124,27 @@ class ForNode(Node):
return nodelist.render(context) return nodelist.render(context)
class IfChangedNode(Node): class IfChangedNode(Node):
def __init__(self, nodelist): def __init__(self, nodelist, *varlist):
self.nodelist = nodelist self.nodelist = nodelist
self._last_seen = None self._last_seen = None
self._varlist = varlist
def render(self, context): def render(self, context):
if context.has_key('forloop') and context['forloop']['first']: if context.has_key('forloop') and context['forloop']['first']:
self._last_seen = None self._last_seen = None
content = self.nodelist.render(context) try:
if content != self._last_seen: 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) firstloop = (self._last_seen == None)
self._last_seen = content self._last_seen = compare_to
context.push() context.push()
context['ifchanged'] = {'firstloop': firstloop} context['ifchanged'] = {'firstloop': firstloop}
content = self.nodelist.render(context) content = self.nodelist.render(context)
@ -634,9 +644,11 @@ def ifchanged(parser, token):
""" """
Check if a value has changed from the last iteration of a loop. 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 The 'ifchanged' block tag is used within a loop. It has two possible uses.
contents against its previous state and only displays its content if the
value has changed:: 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::
<h1>Archive for {{ year }}</h1> <h1>Archive for {{ year }}</h1>
@ -644,13 +656,22 @@ def ifchanged(parser, token):
{% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a> <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% endfor %} {% 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() bits = token.contents.split()
if len(bits) != 1:
raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
nodelist = parser.parse(('endifchanged',)) nodelist = parser.parse(('endifchanged',))
parser.delete_first_token() parser.delete_first_token()
return IfChangedNode(nodelist) return IfChangedNode(nodelist, *bits[1:])
ifchanged = register.tag(ifchanged) ifchanged = register.tag(ifchanged)
#@register.tag #@register.tag

View File

@ -525,15 +525,28 @@ ifchanged
Check if a value has changed from the last iteration of a loop. 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 The 'ifchanged' block tag is used within a loop. It has two possible uses.
contents against its previous state and only displays its content if the value
has changed:: 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::
<h1>Archive for {{ year }}</h1> <h1>Archive for {{ year }}</h1>
{% for day in days %} {% for date in days %}
{% ifchanged %}<h3>{{ day|date:"F" }}</h3>{% endifchanged %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ day|date:"M/d"|lower }}/">{{ day|date:"j" }}</a> <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% 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 %} {% endfor %}
ifequal ifequal

View File

@ -329,6 +329,21 @@ class Templates(unittest.TestCase):
'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'), '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'), '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 ########################################################### ### IFEQUAL TAG ###########################################################
'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"), 'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"),