2012-02-06 7 views
17

tengo un modelo Data, asociado a una tabla de este modo (El modelo Data se compone de solamente IntegerField):Las columnas personalizadas utilizando Django administrador

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...] 

Quiero tener una mesa django-admin, en sólo lectura que tiene columnas (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] 

La pregunta es: es posible hacer que el uso de django-admin? ¿Cuál es la salida?

Respuesta

28

Puede utilizar los métodos en su Model o su ModelAdmin como artículos para list_display. Ver: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display

Dado que estos métodos también pueden ser útiles fuera del administrador, le sugiero que los agregue a su 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)' 

El atributo short_description determina que el administrador se mostrará como el encabezado de fila para estos métodos. Así, una vez que tenga todo esto en su lugar, sólo es necesario modificar ModelAdmin 's list_display atributo como:

class DataAdmin(admin.ModelAdmin): 
    ... 
    list_display = ('subject', 'get_current_year_sales', 'get_last_year_sales', 'get_current_quarter_sales', 'get_last_quarter_sales') 
+0

última pregunta, si quiero ordenar la columna no funciona porque se trata de métodos y no atributos , ¿cierto? ¡Gracias! – zambotn

+1

echa un vistazo a [esto] (http://stackoverflow.com/questions/2168475/django-admin-how-to-sort-by-one-of-the-custom-list-display-fields-that-has-no -d) y [este] (http://stackoverflow.com/questions/2647632/how-to-allow-sorting-in-the-django-admin-by-a-custom-list-display-field-which- d) –

+0

Verdadero. Puede agregar la capacidad de ordenar diciéndole a django qué campo usar con ' .admin_order_field = 'my_field'', pero no hay un buen campo para vincular en este escenario. –

6

Algo como esto debería funcionar (no probado):

# 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',) 
Cuestiones relacionadas