django-admin: Add extra row with totals django-admin: Add extra row with totals django django

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.