3👍
Most of the code in ActionInChangeFormMixin.change_view()
is specifically setup code for the dropdown list, and thus dead code when used with the template shown above. The logic happens here:
action_form = self.action_form(auto_id=None)
action_form.fields['action'].choices = self.get_action_choices(request)
action_form
creates the actual form – which we don’t want to render anyway. get_action_choices
populates the <select>
with tuples to use as options.
To be as flexible as possible, I’ll introduce a new method, which retrieves only the actions we want to show. Also, let’s get rid of the unnecessary code (the new code is inspired by get_action_choices
):
class ActionInChangeFormMixin(object):
# ...
def get_change_actions(self, request):
return self.get_actions(request)
def change_view(self, request, object_id, form_url='', extra_context=None):
actions = self.get_change_actions(request) or OrderedDict()
extra_context = extra_context or {}
extra_context['change_actions'] = [(name, description % admin.utils.model_format_dict(self.opts))
for func, name, description in six.itervalues(actions)]
return super(ActionInChangeFormMixin, self).change_view(request, object_id, extra_context=extra_context)
In TournamentAdmin
, we can then filter which actions we want to see. In this case, I don’t want to show a button for the bulk delete action:
def get_change_actions(self, request):
result = self.get_actions(request)
del result['delete_selected']
return result
change_form.html
now needs some logic to render the relevant buttons:
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
{% for action_name, action_description in change_actions %}
<li>
<form id="action_{{ action_name }}" action="{% url opts|admin_urlname:'changelist' %}" method="POST">{% csrf_token %}
<input type="hidden" name="action" value="{{ action_name }}">
<input type="hidden" name="_selected_action" value="{{ object_id }}">
<a href="#" onclick="document.getElementById('action_{{ action_name }}').submit(); return false;" title="{{ action_description }}">{{ action_description }}</a>
</form>
</li>
{% endfor %}
{{ block.super }}
{% endblock %}
This uses JavaScript for submitting the form; I don’t think there’s a cleaner way to get the styling right.