django-admin: Add extra row with totals

后端 未结 7 1848
盖世英雄少女心
盖世英雄少女心 2020-12-12 20:50

I\'m using the standard django admin module to display a list of rows. One of the columns is a numerical field. I\'d like to display an extra \'totals\' row that has most of

相关标签:
7条回答
  • 2020-12-12 21:42

    Ok, so there is a way to do this, involving adding in a couple of new template tags and extending the admin templates.

    First off, in your app’s templatetags folder, you create an admin_totals.py file containing a template tag to create a totals row:

    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)
    

    Then you need the template for said row in myapp/totals_row.html (wherever your templates are):

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

    Then you need to wire that into a custom admin template inheriting from Django’s default, such as myapp/mymodel_admin.html:

    {% extends "admin/change_list.html" %}
    
    {% load admin_totals %}
    
    {% block result_list %}
    {{ block.super }}
    {% totals_row cl %}
    {% endblock %}
    

    Finally, you wire that into the configuration in your admin.py file in your app:

    class MyModelAdmin(ModelAdmin):
    
        list_display = ('name', 'date', 'numerical_awesomeness')
        total_functions = {'numerical_awesomeness': sum}
    
        change_list_template = 'myapp/mymodel_admin.html'
    

    That should wire in the custom admin template for your new model, displaying the totals row. You can also extend it with other summary functions other than sum, should you so wish.

    One small point left: the totals row isn’t actually in the results table, because that would require some fairly gnarly copying and pasting of the Django admin templates. For bonus points, you can add in the following smidge of JavaScript to the bottom of your totals_row.html file:

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

    One caveat: all this will only reflect the totals for the items currently displayed, rather than for all items in existence. One way around this is to set list_per_page to some infeasibly large number on your ModelAdmin class, if you don’t mind the potential performance hit.

    0 讨论(0)
提交回复
热议问题