2011-12-17 49 views
28

Estoy usando el módulo de administración django estándar para mostrar una lista de filas. Una de las columnas es un campo numérico. Me gustaría mostrar una fila adicional de 'totales' que tenga la mayoría de las columnas en blanco, a excepción de la columna numérica, que debería ser el total de todos los objetos.django-admin: Agregar fila adicional con totales

¿Hay una manera simple de hacer esto dentro del módulo de administración, o es mejor que haga una vista personalizada para él?

Estoy usando Django 1.2.

+0

Solo para asegurarte: ¿Te refieres a la suma total de todos los objetos _en la página actual_ o _todos los objetos en la base de datos_? –

+0

@lazerscience: me refiero a los objetos que se muestran actualmente (por lo que si aplica un filtro solo mostrará los elementos filtrados) – Claudiu

Respuesta

-3

AFAIK no hay forma de hacerlo sin crear una vista personalizada. El concepto es un poco defectuoso de todos modos, porque un usuario esperaría que dicha fila mostrara el total solo para los objetos visibles, en lugar de todos los objetos en el conjunto de preguntas. Por lo tanto, cualquier paginación daría lugar a confusión.

Como acotación al margen, puede agregar adicionales columnas a una vista de la lista de administradores haciendo algo como lo siguiente:

class ItemAdmin(admin.ModelAdmin): 
    model = Item 

    list_display = ('field1', 'field2', 'extra_field') 

    def extra_field(self, obj): 
     return u'%s' % do_something_with(obj) 
0

si crea una vista personalizada overiding la vista de administración que debe ser capaz de tomar el conjunto de preguntas junto con la información de la página actual y cortar los datos para crear un total apropiado para la página actual. si desea un total verdadero de lo que todavía veo una vista de administrador anulada personalizada como la opción que está buscando.

6

Ok, hay una forma de hacerlo, que implica agregar un par de nuevas etiquetas de plantilla y extender las plantillas de administración.

En primer lugar, en la carpeta de su aplicación templatetags, se crea un archivo admin_totals.py que contiene una etiqueta de plantilla para crear una línea de totales:

from django.template import Library 

register = Library() 

def totals_row(cl): 
    total_functions = getattr(cl.model_admin, 'total_functions', {}) 
    totals = [] 
    for field_name in cl.list_display: 
     if field_name in total_functions: 
      values = [getattr(i, field_name) for i in cl.result_list] 
      totals.append(total_functions[field_name](values)) 
     else: 
      totals.append('') 
    return {'cl': cl, 'totals_row': totals} 
totals_row = register.inclusion_tag("myapp/totals_row.html")(totals_row) 

entonces usted necesita la plantilla para dicha fila en myapp/totals_row.html (donde quiera que sus plantillas están):

<table id="result_totals"> 
    <tfoot> 
     <tr> 
      {% for total in totals_row %}<td>{{ total }}</td>{% endfor %} 
     </tr> 
    </tfoot> 
</table> 

Luego hay que cablear que en una plantilla de administración personalizada que hereda de forma predeterminada de Django, como myapp/mymodel_admin.html:

{% extends "admin/change_list.html" %} 

{% load admin_totals %} 

{% block result_list %} 
{{ block.super }} 
{% totals_row cl %} 
{% endblock %} 

Por último, se cablea que en la configuración en el archivo de admin.py en su aplicación:

class MyModelAdmin(ModelAdmin): 

    list_display = ('name', 'date', 'numerical_awesomeness') 
    total_functions = {'numerical_awesomeness': sum} 

    change_list_template = 'myapp/mymodel_admin.html' 

Eso debería alambre en la plantilla de administración personalizado para su nuevo modelo, que muestra la fila de totales. También puede ampliarlo con otras funciones de resumen que no sean sum, si lo desea.

Un pequeño punto a la izquierda: la fila de totales no está realmente en la tabla de resultados, porque eso requeriría una cierta copia y pegado de las plantillas de administración de Django. Para los puntos de bonificación, se puede añadir en el siguiente pizca de JavaScript para la parte inferior de su totals_row.html archivo:

<script type="text/javascript"> 
    django.jQuery('#result_list').append(django.jQuery('#result_totals tfoot')[0]) 
    django.jQuery('#result_totals').remove() 
</script> 

Una advertencia: todo esto solo reflejan los totales de los elementos que se muestran actualmente, en lugar de para todos los elementos existencia. Una forma de evitar esto es establecer list_per_page en un número inadmisiblemente grande en su clase ModelAdmin, si no le importa el posible golpe de rendimiento.

25

Creo que la forma Django de hacer esto es anular la clase ChangeList que utiliza la aplicación de administración de django. Haga esto en django 1.2 llamando al método get_changelist en su clase de administrador. En mi ejemplo: TomatoAdmin llama a este método devolviendo un calss ChangeList personalizado. Esta clase ChangeList: MyChangeList simplemente agrega un atributo adicional al contexto de change_list.html.

Asegúrese de que change_list.html se encuentra en el directorio siguiente:

app_label/change_list.html 

en el ejemplo de esto es: plantillas/admin/tomate/change_list.html

models.py (un modelo simple con un campo entero)

class CherryTomato(models.Model): 
    name = models.CharField(max_length=100) 
    num_in_box = models.IntegerField() 

admin.py (la clase de administración y una clase de lista de cambios de encargo)

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 (poco relevante solamente, copiar/pegar el existente y extenderlo)

{% 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 Te dejaré cómo diseñar esto de la manera que lo desees.

+0

En realidad, esta es la mejor solución, porque la personalización de ChangeList puede agregar "total" con respecto a los filtros seleccionados. – pista329

+0

Mejor y puede llevarse bien con los filtros :) – elsadek

+0

Esto es casi perfecto para mí. El total también refleja la paginación, ya que entra en el conjunto de consultas. – teewuane

28

Sí, se puede hacer de muchas maneras, pero la mayoría manera django-ist que hacer es:

Primera anula la vista predeterminada de Django lista ... y dar un nuevo directorio de archivo de plantilla

ModelAdmin.changelist_view(self, request, extra_context=None) 
al igual que

:

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) 

lo tanto, usted añada su contexto vista de lista de una 'total' que mantiene su valor total y pasarlo a la plantilla.

if change_list_template se establecerá, django usa esa plantilla, de lo contrario, utiliza la plantilla django estándar.

Si def changelist_view (auto, solicitud, extra_context = None) se llama, Django usa esta función para crear el contenido, de lo contrario, utiliza las vistas de Django por defecto.

A continuación, cree un archivo admin/myapp/extras/sometemplate_change_form.html y coloque su {{total}} en el lugar que desee.

Una guía de cómo override admin templates Y aquí es cómo override admin views

ACTUALIZACIÓN: agrego un simple aggregate para calcular total. puede editarlo para configurarlo según sus necesidades.

ACTUALIZACIÓN 2: opción de anulación plantilla ModelAdmin fija ModelAdmin.change_form_template-ModelAdmin.change_list_template. (gracias c4urself).Sí, pero cambiar la plantilla predeterminada de administración de django es una opción realmente mala, ya que es utilizada por muchos otros administradores de modelos y podría causar problemas si las plantillas relacionadas se actualizan.



NB:
El total no cambia cuando el uso de filtros, véase el comentario a continuación.

+2

Creo que esta es una gran manera de hacerlo, creo que 'change_form_template' debe ser' change_list_template'. Aunque no necesita darle un nombre de plantilla si anula las plantillas de administrador. – c4urself

+3

Dulce, esta es realmente una receta de copiar y pegar que estaba buscando. Solo diría que, en lugar de configurar 'change_list_template' en la clase Admin, solo creo un archivo como:' templates/admin/my_app/my_model/change_list.html', luego en ese archivo solo uso '{% extends ' admin/change_list.html '%} ', y solo reemplaza un solo bloque, como:' {% block result_list%} {{block.super}}

El total es: {{total}} !!!

{% endblock%} '. Convención sobre configuración;) –

+0

incluso usando 'super (MyModelAdmin, self) .get_queryset (solicitud)', el conjunto de preguntas no se actualiza cuando se usan filtros, el 'Total' siempre es para la lista no filtrada, este no es el caso en la respuesta de C4urself que creo que es mejor y más limpia. – elsadek

4

También existe el paquete "django-admin-changelist-stats" que puede proporcionar estadísticas de resumen. Lo utilicé con éxito en un proyecto de Django 1.6.

IMO usa la solución de c4urself para la personalización de plantillas de grano fino, pero si solo tiene agregados (suma/promedio/min/máximo) de tablas que está buscando, entonces esta solución es bastante buena.

Desde su página web

" Esta sencilla aplicación proporciona estadísticas y capacidades de agregación para la vista de administración de lista de cambios de Django. Permite mostrar las estadísticas al final de la página de lista de cambios de una manera fácil, basta con añadir una opción al objeto de modelo de administración. "

Más información, incluyendo ejemplos, en su página web bitbucket repositorio https://bitbucket.org/frankban/django-admin-changelist-stats/src

+0

desafortunadamente esta biblioteca no admite agregados en campos relacionados, p. Suma ('menu__meal__cost') falla – d3vid

2

Este hilo está pasando por un tiempo , pero probablemente no soy el último que está buscando esa característica. Por lo tanto, creé un paquete que hace que sea fácil sumar totales.

Pedido https://github.com/douwevandermeij/admin-totals

Uso:

from admin_totals.admin import ModelAdminTotals 
from django.contrib import admin 
from 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)] 

dude que tenedor y mejorarlo.

Cuestiones relacionadas