Ok, so there is a way to do this, involving adding in a couple of new template tags and extending the admin templates.
First off, in your app’s templatetags
folder, you create an admin_totals.py
file containing a template tag to create a totals row:
from django.template import Library
register = Library()
def totals_row(cl):
total_functions = getattr(cl.model_admin, 'total_functions', {})
totals = []
for field_name in cl.list_display:
if field_name in total_functions:
values = [getattr(i, field_name) for i in cl.result_list]
totals.append(total_functions[field_name](values))
else:
totals.append('')
return {'cl': cl, 'totals_row': totals}
totals_row = register.inclusion_tag("myapp/totals_row.html")(totals_row)
Then you need the template for said row in myapp/totals_row.html
(wherever your templates are):
<table id="result_totals">
<tfoot>
<tr>
{% for total in totals_row %}<td>{{ total }}</td>{% endfor %}
</tr>
</tfoot>
</table>
Then you need to wire that into a custom admin template inheriting from Django’s default, such as myapp/mymodel_admin.html
:
{% extends "admin/change_list.html" %}
{% load admin_totals %}
{% block result_list %}
{{ block.super }}
{% totals_row cl %}
{% endblock %}
Finally, you wire that into the configuration in your admin.py
file in your app:
class MyModelAdmin(ModelAdmin):
list_display = ('name', 'date', 'numerical_awesomeness')
total_functions = {'numerical_awesomeness': sum}
change_list_template = 'myapp/mymodel_admin.html'
That should wire in the custom admin template for your new model, displaying the totals row. You can also extend it with other summary functions other than sum
, should you so wish.
One small point left: the totals row isn’t actually in the results table, because that would require some fairly gnarly copying and pasting of the Django admin templates. For bonus points, you can add in the following smidge of JavaScript to the bottom of your totals_row.html
file:
<script type="text/javascript">
django.jQuery('#result_list').append(django.jQuery('#result_totals tfoot')[0])
django.jQuery('#result_totals').remove()
</script>
One caveat: all this will only reflect the totals for the items currently displayed, rather than for all items in existence. One way around this is to set list_per_page
to some infeasibly large number on your ModelAdmin
class, if you don’t mind the potential performance hit.