开发者

Is there a way to get custom Django admin actions to appear on the "change" view in addition to the "change list" view?

开发者 https://www.devze.com 2022-12-30 00:30 出处:网络
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 \"chan

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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号