2010-05-10 9 views
33

Pensé que por alguna razón esto sería fácil de hacer, pero miré más profundo y parece que no hay una manera directa de permitir a los usuarios ejecutar acciones de administración personalizadas en la vista de "cambio" de una instancia (es decir, cuando solo estás viendo la pantalla de edición para una sola instancia, no la lista de instancias).¿Existe alguna manera de que las acciones de administrador de Django aparezcan en la vista de "cambio" además de en la vista de "cambiar lista"?

¿Estoy pasando por alto una manera fácil de hacer esto? ¿O es mi única opción anular una de las plantillas de administrador (y probablemente el método ModelAdmin.add_view)?

Respuesta

2

Lo que hice fue crear mi propia plantilla MIAPL/plantillas/admin/MyModel/change_form.html:

{% 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 %} 

Así que, básicamente, sólo cambió el bloque "objetos-herramientas", donde la historia y el enlace el enlace "ver en el sitio" es. el resto del change_form.html original permanece intacto. BTW: "original.id" es la identificación del modelo que está editando.

+0

Gracias. Terminé publicando mi propia solución, pero tu comentario en realidad me ayudó a darme cuenta de que solo necesitaba absorberlo y extender esa plantilla. – jsdalton

10

Esto es lo que terminé haciendo.

En primer lugar, me extendió la change_view del objeto ModelAdmin de la siguiente manera:

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

Básicamente sólo estamos reuniendo los datos necesarios para poblar las acciones desplegable de la vista del cambio.

Entonces sólo extendieron change_form.html para el modelo en cuestión:

{% 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 %} 

Esto es casi idéntica a la forma en la sección de acciones de administración se emite en la vista de lista de cambios. Las principales diferencias son: 1) Tuve que especificar una URL para el formulario para publicar, 2) en lugar de una casilla de verificación para especificar qué objeto (s) se debe cambiar, el valor se establece a través de un campo de formulario oculto, y 3) Incluí el CSS para la vista de lista de cambios y pegué las acciones en un div con id. De #changelist, solo para que el cuadro parezca medio aceptable.

No es una gran solución, pero funciona bien y no requiere configuración adicional para acciones adicionales que pueda agregar.

18

Aquí está la actualización y mejora de this respuesta. Funciona con django 1.6 y redirige a su origen.

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): 
    ...... 

Plantilla:

{% 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 %} 
+1

ActionAdminMixin y ActionInChangeFormMixin deben coincidir aquí. También: desde la importación de django.http HttpResponseRedirect – pdenya

+0

Esto me salvó y también funciona en Django 1.7. –

Cuestiones relacionadas