views:

207

answers:

2

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)?

A: 

What I did was create my own MYAPP/templates/admin/MYMODEL/change_form.html template:

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
    <li><a href="{% url MY_COMMAND_VIEW original.id %}" class="historylink" >MY COMMAND</a></li>
  <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
  {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
  </ul>
{% endif %}{% endif %}
{% endblock %}

So I basically only changed the block "object-tools" where the history-link and the "view on site"-link are. the rest of the original change_form.html remains untouched. BTW: "original.id" is the id of the model you are editing.

mawimawi
Thanks. I ended up posting my own solution, but your comment actually helped me realize that I just needed to suck it up and extend that template.
jsdalton
A: 

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.

jsdalton