django-admin: добавить дополнительную строку с итогами - PullRequest
30 голосов
/ 17 декабря 2011

Я использую стандартный модуль администратора django для отображения списка строк. Один из столбцов является числовым полем. Я хотел бы отобразить дополнительную строку «итоги», в которой большинство столбцов пустые, кроме числового столбца, который должен быть общим для всех объектов.

Есть ли простой способ сделать это в модуле администратора, или мне лучше создать для него пользовательский вид?

Я использую Django 1.2.

Ответы [ 7 ]

31 голосов
/ 06 января 2012

Да, вы можете сделать это разными способами, но наиболее распространенным способом для django является:

Сначала переопределите стандартное представление списка django ... И дайте новый каталог файлов шаблона

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

Как:

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)

Итак, вы добавляете свой контекст представления списка как «итоговое», которое сохраняет ваше общее значение, и передаете его в шаблон.

Если change_list_template будет установлен, django использует этот шаблон, в противном случае он использует стандартный шаблон django.

Если def changelist_view (self, request, extra_context = None) вызывается, django использует эту функцию для создания контента, в противном случае он использует представления django по умолчанию.

Затем создайте файл admin/myapp/extras/sometemplate_change_form.html и поместите ваш {{total}} в любое место.

Руководство по переопределению шаблонов администратора А вот как переопределить административные представления

ОБНОВЛЕНИЕ: Я добавляю простое aggregate, чтобы вычислить итог. Вы можете отредактировать его так, чтобы он соответствовал вашим потребностям.

ОБНОВЛЕНИЕ 2 : опция переопределения шаблона ModelAdmin исправлена ​​с ModelAdmin.change_form_template до ModelAdmin.change_list_template. (спасибо c4urself). Да, но изменение шаблона администратора django по умолчанию - это действительно плохой выбор, поскольку он используется многими другими ModelAdmin и может вызвать проблемы при обновлении связанных шаблонов.



NB :
Общая сумма не изменяется при использовании фильтров, см. Комментарий ниже.

25 голосов
/ 05 января 2012

Я думаю, что способ Django сделать это - переопределить класс ChangeList, который использует приложение администратора django. Вы делаете это в django 1.2, вызывая метод get_changelist в вашем классе администратора. В моем примере: TomatoAdmin вызывает этот метод, возвращая пользовательский вызов ChangeList. Этот класс ChangeList: MyChangeList просто добавляет дополнительный атрибут в контекст change_list.html.

Убедитесь, что файл change_list.html находится в следующем каталоге:

app_label/change_list.html

в примере это: templates / admin / tomato / change_list.html

models.py (простая модель с целочисленным полем)

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

admin.py (ваш класс Admin и пользовательский класс ChangeList)

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 (только соответствующий бит, скопировать / вставить существующий и расширить его)

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

Я оставлю на ваше усмотрение, как стилизовать это так, как вы хотите.

6 голосов
/ 27 декабря 2017

Эта тема продолжается некоторое время, но я, вероятно, не последний, кто ищет такую ​​функцию.Поэтому я создал пакет, который облегчает добавление итогов.

Оформление заказа https://github.com/douwevandermeij/admin-totals

Использование:

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

Не стесняйтесь раскошелиться и улучшить его.

6 голосов
/ 05 января 2012

Хорошо, есть способ сделать это, включив добавление пары новых тегов шаблонов и расширение шаблонов администратора.

Прежде всего, в папке templatetags вашего приложения вы создаете файл admin_totals.py, содержащий тег шаблона для создания итоговой строки:

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)

Затем вам понадобится шаблон для указанной строки в myapp/totals_row.html (где бы вы ни находились -):

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

Затем вам нужно подключить его к пользовательскому шаблону администратора, унаследованному от настроек по умолчанию в Django, например myapp/mymodel_admin.html:

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

{% load admin_totals %}

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

Наконец, вы подключаете это к конфигурации в файле admin.py в вашем приложении:

class MyModelAdmin(ModelAdmin):

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

    change_list_template = 'myapp/mymodel_admin.html'

Это должно подключить пользовательский шаблон администратора для вашей новой модели, отображающий итоговую строку. Вы также можете расширить его другими функциями сводки, кроме sum, если хотите.

Осталась одна небольшая точка: строка итогов на самом деле отсутствует в таблице результатов, потому что это потребовало бы довольно грубого копирования и вставки шаблонов администратора Django. Для получения бонусных баллов вы можете добавить следующий фрагмент JavaScript в конец файла totals_row.html:

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

Одно предостережение: все это будет отражать только итоги по отображаемым элементам, а не по всем существующим элементам. Одним из способов решения этой проблемы является установка list_per_page на какое-то невероятно большое число в классе ModelAdmin, если вы не возражаете против потенциального снижения производительности.

4 голосов
/ 23 марта 2015

Существует также пакет "django-admin-changelist-stats", который может предоставить сводную статистику.Я успешно использовал его в проекте Django 1.6.

IMO использует решение c4urself для детальной настройки шаблонов, но если его единственные агрегаты (сумма / avg / min / max) таблиц, то вы после этого решениядовольно хорошо.

С его сайта

"Это простое приложение предоставляет статистику и возможности агрегирования для представления списка изменений администратора Django. Оно позволяет легко отображать статистику в конце страницы списка изменений.Кстати, просто добавив одну опцию к объекту администратора модели. "

Дополнительную информацию, включая примеры, можно найти на веб-странице репозитория bitbucket https://bitbucket.org/frankban/django-admin-changelist-stats/src

0 голосов
/ 18 декабря 2011

если вы создаете пользовательское представление, выходящее за пределы представления администратора, вы должны иметь возможность взять набор запросов вместе с информацией о текущей странице и срезать данные, чтобы создать общее количество, соответствующее текущей странице. если вы хотите получить истинную сумму, я по-прежнему вижу настраиваемое переопределенное представление администратора в качестве опции, которую вы ищете.

0 голосов
/ 17 декабря 2011

AFAIK, нет способа сделать это без создания собственного представления. В любом случае, эта концепция немного ошибочна, поскольку пользователь ожидает, что в такой строке будет отображаться сумма только для видимых объектов, а не для всех объектов в наборе запросов. Таким образом, любая нумерация страниц может привести к путанице.

Кроме того, вы можете добавить дополнительные столбцы в представление списка администратора, выполнив что-то вроде следующего:

class ItemAdmin(admin.ModelAdmin):
    model = Item

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

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