Add checkbox and delete actions to customized Django admin change_list

The key is to look at the "admin/change_list.html" template that is extended in "sale_summary_change_list.html". Its result_list block has the needed form. You will also have to add the input checkboxes to the returned query set in admin.py/changelist_view. I modified the code from the tutorial. We of course have to drop the aggregation on sales if we want to be able to delete individual items.

from django.contrib import admin
from django.contrib.admin import ModelAdmin, helpers

from .models import SaleSummary, Category


@admin.register(SaleSummary)
class SaleSummaryAdmin(ModelAdmin):
    change_list_template = 'admin/sale_summary_change_list.html'
    date_hierarchy = 'date'

    def changelist_view(self, request, extra_context=None):
        response = super(SaleSummaryAdmin, self).changelist_view(
            request,
            extra_context=extra_context,
        )
        try:
            qs = response.context_data['cl'].queryset
        except (AttributeError, KeyError):
            return response

        # metrics = {
        #     'total': Count('id'),
        #     'total_sales': Sum('amount'),
        # }
        result_qs = list(qs.values('category__name', 'pk', 'amount').order_by('category__name').all())
        map(lambda r: r.update(
            {'check_box': helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, r['pk'])}), result_qs)
        response.context_data['summary'] = list(result_qs)

        return response

And here is the template:

{% extends "admin/change_list.html" %}
{% load humanize admin_list%}
{% block content_title %}
    <h1> Sales Summary </h1>
{% endblock %}

{% block result_list %}

          {% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %}
          {% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %}
    <div class="results">
        <table>
            <thead>
            <tr>
                <th>
                    <div class="text">
                        <a href="#">Action</a>
                    </div>
                </th>
                <th>
                    <div class="text">
                        <a href="#">Category</a>
                    </div>
                </th>
                <th>
                    <div class="text">
                        <a href="#">Total Sales</a>
                    </div>
                </th>
            </tr>
            </thead>
            <tbody>
            {% for row in summary %}
                <tr class="{% cycle 'row1' 'row2' %}">
                    <td> {{ row.check_box }} </td>
                    <td> {{ row.category__name }} </td>
                    <td> {{ row.amount | intcomma }} </td>

                </tr>
            {% endfor %}
            </tbody>

        </table>
    </div>

{% endblock %}

{% block pagination %}{% endblock %}

Check the complete project on github:

https://github.com/SabirAkhadov/django-action-change-list-demo


@Sabir Answer is the best one, and this one builds on top of it.

The part where he uses map to append the checkbox to the result list can give some performance issues when you are dealing with so many rows, let say 1000 rows

I found that : You can render the checkbox on the front end, and pass it the element pk.

You can keep the same admin class but remove the map line in the change_list_view function and let the front end to the job.

So I changed my template like this

{% extends "admin/change_list.html" %}
{% load humanize admin_list%}
{% block content_title %}
    <h1> Sales Summary </h1>
{% endblock %}

{% block result_list %}

          {% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %}
          {% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %}
    <div class="results">
        <table>
            <thead>
            <tr>
                <th>
                    <div class="text">
                        <a href="#">Action</a>
                    </div>
                </th>
                <th>
                    <div class="text">
                        <a href="#">Category</a>
                    </div>
                </th>
                <th>
                    <div class="text">
                        <a href="#">Total Sales</a>
                    </div>
                </th>
            </tr>
            </thead>
            <tbody>
            {% for row in summary %}
                <tr class="{% cycle 'row1' 'row2' %}">
                    <td> <td> <input type="checkbox" name="_selected_action" value={{row.pk}} class="action-select"> </td> </td>
                    <td> {{ row.category__name }} </td>
                    <td> {{ row.amount | intcomma }} </td>

                </tr>
            {% endfor %}
            </tbody>

        </table>
    </div>

{% endblock %}

{% block pagination %}{% endblock %}