Django Models and Templates

When doing web development, you tend to lose a lot of flexibility regardless of the framework that you’re working with. You end up doing things the “Django-way” or the “RoR-way”.  That became painfully clear to me this weekend while I was working on my CSC309 assignment.

The Model

Let’s say that you have a model called classroom with keys first_name, last_name and class:

classroom = [
	{'first_name': 'Bob', 'last_name': 'Lee', 'class': '4a'},
	{'first_name': 'Jack', 'last_name': 'Smith', 'class': '4a'},
	{'first_name': 'Jill', 'last_name': 'Schmidt', 'class': '4b'},
	{'first_name': 'Alice', 'last_name': 'White', 'class': '4b'},
	{'first_name': 'Eve', 'last_name': 'Thrace', 'class': '4b'},
	{'first_name': 'Doug', 'last_name': 'Chan', 'class': '4c'},
]

And you need to make a query so that you can group every student by their class so you get something like:

4a: {'first_name': Bob, 'last_name': Lee},
     {'first_name': 'Jack', 'last_name': 'Smith}
4b: {'first_name': 'Jill', 'last_name': 'Schmidt'},
     {'first_name': 'Alice', 'last_name': 'White'},
     {'first_name': 'Eve', 'last_name': 'Thrace'}
4c: {'first_name': 'Doug', 'last_name': 'Chan'}

Query?

If you were working directly with something like Postgres, all you database-heads out there will say to yourself: “oh yeah, you can just do select on rows XYZ and then do a crosstab on columns QTY…etc, etc”.

Well, that’s good and all, but the Django Model isn’t exactly sophisticated enough to let you do that. The only way to go would be to tell Django to execute a raw SQL query. But that means I’d have to write the query, and frankly my SQL skills are *ahem* kinda rusty.

There has got to be another way to do this…right?

Regroup Template Tag

Surprisingly, the solution lies in neither the Model nor the View, but in Django’s Template Tag system. Yeah, I know, that makes total sense 8O

The regroup template tag is a built-in template tag, so you can use it out-of-the-box. You can read the boring bits on the Django documentation site: http://docs.djangoproject.com/en/dev/ref/templates/builtins/?PHPSESSID=43163c04aafc5388c9c4cbe22dabaf3e

Basically, you want to pass your database as-is to your template and then do the reorganization inside the template.

{% regroup classroom by class as class_list %}
{% for c in class_list %}

        {{c.grouper }}

	{% for student in c.list %}
                {{ student.first_name }}, {{ student.last_name }}
	{% endfor %}

{% endfor %}
  • Line 1 tells Django to regroup everything by the key class. A list of group objects are created and dumped into class_list
  • Line 2 iterates over the list of group objects
  • Line 4: For each item in class_list, we access the grouper item. The grouper tells us which class the current c is grouped by, we access this purely for display purposes
  • Line 6 – 8: Print out the class names!

The output should look something like:

4a
Bob, Lee
Jack, Smith

4b
Jill, Schmidt
Alice, White
Eve, Thrace

4c
Doug, Chan

Okay it probably doesn’t but you get the idea!

Ordering

One of the caveats with this is that the database must already be sorted on the key that you’re regrouping on, or else regroup will not behave as you expected. You can solve this by using the dictsort filter:

{% regroup classroom|dictsort:"class" by class as class_list %}

Convoluted Enough?

So there we have it, we were able to reorder our table exactly how we want it. The steps to do it were convoluted as hell, and the feature isn’t exactly highly advertised. I had to hunt through Google and StackOverflow for quite a bit before I found this solution. In retrospect, I probably could have used that time to hammer out a nice SQL query, but I think it was worth it to find out about this nice tag!

This entry was posted in Django, Tech, python and tagged , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>