Django iflt, ifgt template tags
In Django, one has the ifchanged template tag that can be used to render content only when some loop variable has changed. I did a small extension of this by implementing the ifgt and iflt block template tags, that render their blocks only when some loop variable has increased or decreased.
I used this for my SnookerData pet project, in which I wanted to present the ranking of a snooker player after each ranking tournament in the season. Then, when the ranking had improved, I wanted to have a green “up” icon next to the entry, and when the ranking had become worse, I wanted a red “down” icon. See here for an example.
As it happens, this is pretty easy to implement: I used the code for ifchanged as a basis and made some small modifications to make it have the decribed functionality. The resulting code can be found here. To install, create a templatetags subdirectory of your Django application, and place an empty __init__.py and the changecompare.py file in it.
The interesting part of the implementation is the IfGreaterNode class. This node is the part of the parse tree representing the iflt or ifgt block template tag. Every time it needs to be rendered, it checks the value of the variable against the previous value and renders its contents if they satisfy the condition:
if self._last_seen != None: if (self.isgreater and compare_to > self._last_seen) or (not self.isgreater and compare_to < self._last_seen): self._last_seen = compare_to content = self.nodelist_true.render(context) return content self._last_seen = compare_to return ''
One thing to notice is that to store the last value, the element needs to be rendered. Thus, if the ifgt or iflt part is in a conditional part of the loop block, then the value of the variable is compared to the previous value when the given condition was met.
As an example of how to use this: first, we load the tag library:
{% load changecompare %}Next, we can check whether the ranking of our snooker player has improved or deteriorated, and add an appropriate icon. The complete for loop is as follows:
<table>
{% for r in rank %}
<tr>
<td>
{% ifgt r.position %}<img src="/data/reddown.jpg"
width="8" height="8" alt="Down" />{% endifgt %}
{% iflt r.position %}<img src="/data/greenup.jpg"
width="8" height="8" alt="Up"/>{% endiflt %}
</td>
{% if r.tournament %}
<td>{{ r.tournament.name }}</td>
{% else %}
<td><b>Season starting points:</b></td>
{% endif %}
<td>#{{ r.position }}</td><td>{{ r.points }}</td>
</tr>
{% endfor %}
</table>As mentioned, this gives the expected result. Nice!
Comments (No comments)
What do you think?