Reputation: 785
I have a model Data
, associated to a table like this (The model Data
is made up of only IntegerField):
subject | year | quarter | sales |
----------------------------------
1 | 2010 | 1 | 20 |
1 | 2010 | 2 | 100 |
1 | 2010 | 3 | 100 |
1 | 2010 | 4 | 20 |
1 | 2011 | 1 | 30 |
1 | 2011 | 2 | 50 |
1 | 2011 | 4 | 40 |
2 | 2010 | 1 | 30 |
2 | 2010 | 2 | 20 |
[..-GO ON this way...]
I want to have a django-admin table, in read-only having columns (current year = 2011, quarter = 1
)
subject | sales current year | sales current quarter | sales last year | sales current quarter last year |
----------------------------------------------------------------------------------------------------------
1 | 110 | 30 | 240 | 20
[AND SO ON]
The question is: It is possible do that using django-admin? What's the way out?
Upvotes: 23
Views: 34586
Reputation: 14180
Something like this should work (untested):
# models.py
class Data(models.Model):
year = models.DateField()
sales = models.IntegerField()
# ...
def sales_current_year(self):
return self.model._default_manager.get_queryset().filter(year=2012).annotate(Sum('sales'))
# admin.py
class DataAdmin(admin.ModelAdmin):
list_display = ('sales_current_year',)
Upvotes: 10
Reputation: 239250
You can use methods on your Model
or your ModelAdmin
as items for list_display
. See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
Since these are methods that might be useful outside the admin, as well, I'd suggest adding them to your Model
.
from django.db.models import Sum
class Data(models.Model):
...
# Method used by `get_current_year_sales` and `get_last_year_sales`
# to stay DRY. Not for use directly in admin.
def get_year_sales(self, year):
qs = self.model._default_manager.filter(year=year)
sales_agg = qs.aggregate(Sum('sales'))
return sales_agg['sales__sum']
# Method used by `get_current_quarter_sales` and `get_last_quarter_sales`
# to stay DRY. Not for use directly in admin.
def get_quarter_sales(self, year, quarter):
qs = self.model._default_manager.filter(year=year, quarter=quarter)
sales_agg = qs.aggregate(Sum('sales'))
return sales_agg['sales__sum']
def get_current_year_sales(self):
return self.get_year_sales(datetime.now().year)
get_current_year_sales.short_description = 'Sales (Current Year)'
def get_last_year_sales(self):
return self.get_year_sales(datetime.now().year-1)
get_last_year_sales.short_description = 'Sales (Last Year)'
def get_current_quarter_sales(self):
# Determine current quarter logic here as `current_quarter`
# `quarter_year` will likely be same as current year here,
# but will need to be calculated for previous quarter
return self.get_quarter_sales(quarter_year, current_quarter)
get_current_quarter_sales.short_description = 'Sales (Current Quarter)'
def get_current_quarter_sales(self):
# Logic here to determine last quarter as `last_quarter`
# Logic to determine what year last quarter was in as `quarter_year`
return self.get_quarter_sales(quarter_year, last_quarter)
get_last_quarter_sales.short_description = 'Sales (Last Quarter)'
The short_description
attribute determines what the admin will show as the row header for these methods. So, once you have all this in place, you need only modify your ModelAdmin
's list_display
attribute like:
class DataAdmin(admin.ModelAdmin):
...
list_display = ('subject', 'get_current_year_sales', 'get_last_year_sales', 'get_current_quarter_sales', 'get_last_quarter_sales')
Upvotes: 42