I've been customizing Django
's change_list.html
following this tutorial. My question concerns something that wasn't covered in that tutorial:
How to easily add the checkbox
and the actions
(delete selected items)?
I took a look in the templatetags
of the admin section (mainly here, but I couldn't understand how to easily add the delete action to each item in a customized change_list.html
template and what should be added to the ModelAdmin
class).
Update:
Below is the custom change_list.html
, I'm trying to add item checkboxes to:
{% extends "admin/change_list.html" %}
{% block content_title %}
<h1>Title</h1>
{% endblock %}
{% block result_list %}
<div class="results">
<table id="result_list">
<thead>
...
</thead>
<tbody>
{% for item in items %}
<tr class="{% cycle 'row1' 'row2' %}">
...
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
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 %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With