6👍
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
1👍
@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 %}
- Django pre_save signal does not work
- Cannot install "psycopg2" on Windows 10 with Python 3.8
- Filter Django Haystack results like QuerySet?
- Django Admin, accessing reverse many to many