django-admin: Add extra row with totals
Yes, you can do it in many ways, but most django-ist way to do is:
First override the default django listing view... And give a new template file directory
ModelAdmin.changelist_view(self, request, extra_context=None)
Like:
class MyModelAdmin(admin.ModelAdmin): # A template for a very customized change view: change_list_template = 'admin/myapp/extras/sometemplate_change_form.html' def get_total(self): #functions to calculate whatever you want... total = YourModel.objects.all().aggregate(tot=Sum('total'))['tot'] return total def changelist_view(self, request, extra_context=None): my_context = { 'total': self.get_total(), } return super(MyModelAdmin, self).changelist_view(request, extra_context=my_context)
So, you add your list view context a 'total' that keeps your total value and pass it to the template.
if change_list_template will set, django uses that template, otherwise, it uses standard django template.
If def changelist_view(self, request, extra_context=None) is called, django uses that function to create the content, otherwise it uses default django views.
Then create a admin/myapp/extras/sometemplate_change_form.html
file and place your {{total}}
to any place you want.
A guide to how to override admin templatesAnd here is how to override admin views
UPDATE: I add a simple aggregate
to calculate total. you can edit it to set it as your needs.
UPDATE 2: ModelAdmin template override option fixed from ModelAdmin.change_form_template
to ModelAdmin.change_list_template
. (thank you c4urself). Yes, but changing the default django admin template is a really bad choice, since it is used by many other ModelAdmin's and it might cause problems if related templates are updated.
NB:
The Total doesn't change when using filters, see comment below.
I think the Django way to do this is to override the ChangeList class which django's admin app uses. You do this in django 1.2 by calling the get_changelist
method in your admin class. In my example: TomatoAdmin
calls this method returning a custom ChangeList calss. This ChangeList class: MyChangeList
simply adds an extra attribute to the context of change_list.html
.
Make sure that change_list.html is in the following directory:
app_label/change_list.html
in the example this is: templates/admin/tomato/change_list.html
models.py (A simple model with an integer field)
class CherryTomato(models.Model): name = models.CharField(max_length=100) num_in_box = models.IntegerField()
admin.py (your Admin class and a custom ChangeList class)
from django.contrib import adminfrom django.contrib.admin.views.main import ChangeListfrom django.db.models import Count, Sumfrom tomatoes.tomato.models import CherryTomatoclass MyChangeList(ChangeList): def get_results(self, *args, **kwargs): super(MyChangeList, self).get_results(*args, **kwargs) q = self.result_list.aggregate(tomato_sum=Sum('num_in_box')) self.tomato_count = q['tomato_sum']class TomatoAdmin(admin.ModelAdmin): def get_changelist(self, request): return MyChangeList class Meta: model = CherryTomato list_display = ('name', 'num_in_box')admin.site.register(CherryTomato, TomatoAdmin)
change_list.html (relevant bit only, copy/paste the existing one and extend it)
{% block result_list %} {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %} {% result_list cl %} {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %} Tomatoes on this page: {{ cl.tomato_count }} {% endblock %}
I'll leave it up to you how to style this the way you want it.
This thread is going on for a while, but I'm probably not the last one that is looking for such a feature. Therefore, I created a package that makes it easy to add totals.
Checkout https://github.com/douwevandermeij/admin-totals
Usage:
from admin_totals.admin import ModelAdminTotalsfrom django.contrib import adminfrom django.db.models import Sum, Avg@admin.register(MyModel)class MyModelAdmin(ModelAdminTotals): list_display = ['col_a', 'col_b', 'col_c'] list_totals = [('col_b', Sum), ('col_c', Avg)]
Feel free to fork it and improve it.