In a Django application, I want to display a multi-level (but fixed-depth) tree of model objects in table form. The HTML would look something like this:
<tr><td rowspan="2">group 1</td><td>item 1.1</td></tr>
<tr><td>item 1.2</td></tr>
<tr><td rowspan="3">group 2</td><td>item 2.1</td></tr>
<tr><td>item 2.2</td></tr>
<tr><td>item 2.3</td></tr>
The problem is filling in the rowspan. It's easy enough for two levels: you just use group.item_set.count. But let's say we have another level after items (eg subitem 1.1.1 etc.): then the rowspan of the "group 1" cell needs to be the count of all items plus the sum of all subitems within all items. It's easy enough to calculate using an aggregate, but I can't use aggregates in Django's template language.
That leaves a few options:
- Add a
count_all_subitems
method to the Group model class. However, it seems wrong to put extra code in the model just because the view layer needs it. - Generate a dictionary or list of subitem counts in the view function and pass it as extra contex; however, Django's template language does not allow the key/index in a dictionary/list lookup to be a variable (eg,
subitem_counts.group
doessubitem_counts['group']
, and there's no way to make it dosubitem_counts[group]
AFAIK), so this requires a custom filter. - Write a custom filter or tag that calculates and outputs the subitem count (or the entire rowspan value) directly.
I know Django is designed to avoid having much logic in the templates, and instead recommends putting it in the view function, but it seems that I still need an extra piece (a custom template filter or tag) to actually use the results in a template. What's the preferred approach?