Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Regroup vs. IfChanged in Django templates

Jerry Stratton, June 24, 2008

This might be one of those things that is obvious to everyone but me, but I have a tendency to forget about Django’s regroup functionality. In this particular case, I wanted to make an alphabetical list of page titles, separated by a headline for each letter of the alphabet represented. My first attempt used IfChanged:

[toggle code]

  • <ul>
    • {% for item in page.family %}
      • {% ifchanged %}</ul><h2 id="{{item.title|first|upper}}">{{ item.title|first|upper }}</h2><ul>{% endifchanged %}
      • <li><a href="{{ item.url }}">{{ item.title }}</a></li>
    • {% endfor %}
  • </ul>

I should have realized I was doing something wrong when I had to put in an empty list (before the letter “A”) to make it worked with IfChanged. It only became obvious for me, though, when I tried to add a “top” link at the bottom of each section of the alphabet. IfChanged wasn’t going to be able to handle it, because the letter “A” shouldn’t have a “top” link above it. I could use forloop.first, but then the IfChanged section would change between the first A item and the second A item, resulting in two headlines for the letter A.

I went to the Django template language for template authors page to see if there was a solution; there was (IfChanged can take a variable name) but I noticed regroup and wondered if it might be more appropriate. I’ve used it before, but not with filters. The documentation doesn’t mention using filters with the “by” portion of regroup, but I thought I’d flail around a bit. Turns out it works. If I “regroup page.familyIndex by title|first|upper as letters” I get a listing of each first letter represented in the titles.

[toggle code]

  • {% regroup page.family by title|first|upper as letters %}
  • {% for letter in letters %}
    • <h2 id="{{ letter.grouper }}">{{ letter.grouper }}</h2>
    • <ul>
      • {% for item in letter.list %}
        • <li><a href="{{ item.url }}">{{ item.title }}</a></li>
      • {% endfor %}
      • <li class="topper"><a href="#top">(top)</a></li>
    • </ul>
  • {% endfor %}

No more empty list and no problem adding a special link at the bottom of each letter of the alphabet.

  1. <- Apache Brigades
  2. Leopard PIL ->