Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-admin: Add extra row with totals

I'm using the standard django admin module to display a list of rows. One of the columns is a numerical field. I'd like to display an extra 'totals' row that has most of the columns as blank, except for the numerical column, which should be the total for all of the objects.

Is there a simple way to do this within the admin module, or am I better off making a custom view for it?

I'm using Django 1.2.

like image 470
Claudiu Avatar asked Dec 17 '11 01:12

Claudiu


People also ask

Can we customize Django admin panel?

The Django admin is a powerful built-in tool giving you the ability to create, update, and delete objects in your database using a web interface. You can customize the Django admin to do almost anything you want.

What is Inlines in Django?

django-inline-actions provides a handy templatetag render_inline_action_fields , which adds these information as hidden fields to a form. As the action does not know that an intermediate form is used, we have to include some special handling.

What we can do in admin portal in Django?

Overview. The Django admin application can use your models to automatically build a site area that you can use to create, view, update, and delete records. This can save you a lot of time during development, making it very easy to test your models and get a feel for whether you have the right data.

Is Django's admin interface customizable if yes then how?

To implement it in your project, make a new app in your Django project named products. Install this application, type product in the INSTALLED_APPS list in settings.py file. We will now make models in the products app. The model will be used throughout the tutorial to customize the Django Admin.


2 Answers

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 templates And 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.

like image 93
FallenAngel Avatar answered Sep 20 '22 13:09

FallenAngel


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 admin from django.contrib.admin.views.main import ChangeList from django.db.models import Count, Sum  from tomatoes.tomato.models import CherryTomato  class 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.

like image 31
c4urself Avatar answered Sep 18 '22 13:09

c4urself