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
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!
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
classroomwith keysfirst_name,last_nameandclass: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
classso 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
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 %}class. A list ofgroupobjects are created and dumped intoclass_listgroupobjectsclass_list, we access thegrouperitem. The grouper tells us whichclassthe currentcis grouped by, we access this purely for display purposesThe output should look something like:
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
dictsortfilter:{% 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!