I thought for whatever reason this would be easy to do, but I looked deeper and it appears there is no straightforward way to allow users to execute custom admin actions on the "change" view of an instance (i.e. when you are just viewing the edit screen for a single instance, not the list of instances).
Am I overlooking an easy way to do this? Or is my only choice to override one of the admin templates (and probably the ModelAdmin.add_view
method)?
To do so, you will have to change the project's settings.py . Find the TEMPLATES section and modify accordingly. To override the default template you first need to access the template you want to modify from the django/contrib/admin/templates/admin directory.
One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin's recommended use is limited to an organization's internal management tool.
Here is update and improvement of this answer. It works with django 1.6 and redirects to where you came from.
class ActionInChangeFormMixin(object): def response_action(self, request, queryset): """ Prefer http referer for redirect """ response = super(ActionInChangeFormMixin, self).response_action(request, queryset) if isinstance(response, HttpResponseRedirect): response['Location'] = request.META.get('HTTP_REFERER', response.url) return response def change_view(self, request, object_id, extra_context=None): actions = self.get_actions(request) if actions: action_form = self.action_form(auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) else: action_form = None extra_context=extra_context or {} extra_context['action_form'] = action_form return super(ActionInChangeFormMixin, self).change_view(request, object_id, extra_context=extra_context) class MyModelAdmin(ActionInChangeFormMixin, ModelAdmin): ......
Template:
{% extends "admin/change_form.html" %} {% load i18n admin_static admin_list admin_urls %} {% block extrastyle %} {{ block.super }} <link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}" /> {% endblock %} {% block object-tools %} {{ block.super }} <div id="changelist"> <form action="{% url opts|admin_urlname:'changelist' %}" method="POST">{% csrf_token %} {% admin_actions %} <input type="hidden" name="_selected_action" value="{{ object_id }}"> </form> </div> {% endblock %}
Here's what I ended up doing.
First, I extended the change_view of the ModelAdmin object as follows:
def change_view(self, request, object_id, extra_context=None): actions = self.get_actions(request) if actions: action_form = self.action_form(auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) else: action_form = None changelist_url = urlresolvers.reverse('admin:checkout_order_changelist') return super(OrderAdmin, self).change_view(request, object_id, extra_context={ 'action_form': action_form, 'changelist_url': changelist_url })
Basically we're just gathering the data needed to populate the actions dropdown on the change view.
Then I just extended change_form.html for the model in question:
{% extends "admin/change_form.html" %} {% load i18n adminmedia admin_list %} {% block extrastyle %} {{ block.super }} <link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" /> {% endblock %} {% block object-tools %} {{ block.super }} <div id="changelist"> <form action="{{ changelist_url }}" method="POST">{% csrf_token %} {% admin_actions %} <input type="hidden" name="_selected_action" value="{{ object_id }}"> </form> </div> {% endblock %}
This is almost identical to how the admin actions section is outputted on the change list view. The main differences are: 1) I had to specify a URL for the form to post to, 2) instead of a checkbox to specify which object(s) should be changed, the value is set via a hidden form field, and 3) I included the CSS for the change list view, and stuck the actions in a div with id of #changelist
-- just so the box would look halfway decent.
Not a great solution, but it works okay and requires no additional configuration for additional actions you might add.
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