it-swarm-pt.tech

django-admin: Adicione linha extra com totais

Estou usando o padrão Django para exibir uma lista de linhas. Uma das colunas é um campo numérico. Gostaria de exibir uma linha 'totais' extra que tenha mais de as colunas em branco, exceto a coluna numérica, que deve ser o total para todos os objetos.

Existe uma maneira simples de fazer isso no módulo de administração ou é melhor criar uma exibição personalizada para ele?

Estou usando Django 1.2.

33
Claudiu

Sim, você pode fazer isso de várias maneiras, mas a maioria das maneiras de fazer o Django é:

Primeiro, substitua a exibição de listagem padrão Django ... E forneça um novo diretório de arquivo de modelo

ModelAdmin.changelist_view(self, request, extra_context=None)

Gostar:

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)

Portanto, você adiciona ao contexto de exibição de lista um 'total' que mantém seu valor total e o passa para o modelo.

se change_list_template será definido, Django usa esse modelo, caso contrário, ele usa o modelo Django padrão.

Se def changelist_view (self, request, extra_context = None) é chamado, Django usa essa função para criar o conteúdo, caso contrário, usa as visualizações padrão Django.

Em seguida, crie um arquivo admin/myapp/extras/sometemplate_change_form.html E coloque seu {{total}} Em qualquer lugar que desejar.

Um guia sobre como substituir modelos de administração E aqui está como substituir visualizações de administrador

UPDATE: Eu adiciono um simples aggregate para calcular o total. você pode editá-lo para configurá-lo conforme suas necessidades.

ATUALIZAÇÃO 2: a opção de substituição do modelo ModelAdmin foi corrigida de ModelAdmin.change_form_template Para ModelAdmin.change_list_template. (obrigado a si mesmo). Sim, mas alterar o modelo de administração padrão Django é uma péssima escolha, pois é usado por muitos outros ModelAdmin e pode causar problemas se os modelos relacionados forem atualizados.



[~ # ~] nb [~ # ~]:
O total não muda ao usar filtros, veja o comentário abaixo.

31
FallenAngel

Eu acho que a maneira Django para fazer isso é substituir a classe ChangeList que o aplicativo de administração do Django usa. Você faz isso em Django 1.2 chamando o get_changelist método na sua classe de administrador. No meu exemplo: TomatoAdmin chama esse método retornando uma alteração personalizada de ChangeList. Esta classe ChangeList: MyChangeList simplesmente adiciona um atributo extra ao contexto de change_list.html.

Verifique se change_list.html está no seguinte diretório:

app_label/change_list.html

no exemplo, é: templates/admin/tomato/change_list.html

models.py (Um modelo simples com um campo inteiro)

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

admin.py (sua classe Admin e uma classe ChangeList personalizada)

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 (somente bit relevante, copie/cole o existente e o estenda)

  {% 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 %}

Vou deixar para você como estilizar isso do jeito que você quiser.

25
c4urself

Ok, existe uma maneira de fazer isso, envolvendo a adição de algumas novas tags de modelo e a extensão dos modelos de administrador.

Primeiro, na pasta templatetags do seu aplicativo, você cria uma admin_totals.py arquivo contendo uma tag de modelo para criar uma linha de totais:

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)

Então você precisa do modelo para a referida linha em myapp/totals_row.html (onde quer que seus modelos estejam):

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

Em seguida, você precisa conectá-lo a um modelo de administrador personalizado herdado do padrão do Django, como myapp/mymodel_admin.html:

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

{% load admin_totals %}

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

Por fim, você conecta isso à configuração em seu admin.py arquivo no seu aplicativo:

class MyModelAdmin(ModelAdmin):

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

    change_list_template = 'myapp/mymodel_admin.html'

Isso deve conectar o modelo de administrador personalizado para o seu novo modelo, exibindo a linha de totais. Você também pode estendê-lo com outras funções de resumo diferentes de sum, se desejar.

Um pequeno ponto restante: a linha de totais não está realmente na tabela de resultados, porque isso exigiria algumas cópias e colagens razoavelmente complicadas dos modelos de administração Django admin. Para obter pontos de bônus, você pode adicionar o seguinte fragmento de JavaScript na parte inferior do seu totals_row.html Arquivo:

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

Uma ressalva: tudo isso refletirá apenas os totais dos itens exibidos no momento, em vez de todos os itens existentes. Uma maneira de contornar isso é definir list_per_page para um número invulgarmente grande na sua classe ModelAdmin, se você não se importa com o possível impacto no desempenho.

7
FatBusinessman

Esse tópico está em andamento por um tempo, mas provavelmente não sou o último a procurar esse recurso. Portanto, criei um pacote que facilita a adição de totais.

Checkout 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)]

Sinta-se livre para bifurcá-lo e melhorá-lo.

6
Douwe van der Meij

Há também o pacote "Django-admin-changelist-stats" que pode fornecer estatísticas resumidas. Eu usei com sucesso em um projeto Django 1.6.

A IMO usa a solução do c4urself para personalização de modelos refinada, mas se seus únicos agregados (soma/média/min/max) de tabelas estiverem em seguida, essa solução será muito boa.

Do seu site

"Este aplicativo simples fornece estatísticas e recursos de agregação para a exibição da lista de alterações do administrador [Django _. Permite exibir estatísticas no final da página da lista de alterações de uma maneira fácil, apenas adicionando uma opção ao objeto de administração do modelo."

Mais informações, incluindo exemplos, na página do repositório bitbucket https://bitbucket.org/frankban/Django-admin-changelist-stats/src

4
Sachin

se você criar uma visualização personalizada que substitua a visualização de administrador, poderá levar o conjunto de consultas com as informações da página atual e dividir os dados para criar um total apropriado à página atual. se você deseja um total verdadeiro, ainda vejo uma visualização de administrador substituída personalizada como a opção que você está procurando.

0
Dave LeBlanc