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

后端 未结 3 695
一整个雨季
一整个雨季 2021-02-01 02:58

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

相关标签:
3条回答
  • 2021-02-01 03:21

    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.

    0 讨论(0)
  • 2021-02-01 03:23

    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 %}
    
    0 讨论(0)
  • 2021-02-01 03:23

    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 讨论(0)
提交回复
热议问题