web-dev-qa-db-fra.com

Django: Comment ajouter un bouton personnalisé à la page du formulaire de changement d'administrateur qui exécute une action d'administration?

J'ai déjà défini une action d'administration personnalisée pour mon modèle qui fonctionne parfaitement comme prévu. J'ai également examiné plusieurs façons d'ajouter un bouton à la page du formulaire de changement d'administrateur ici sur SO. La seule étape qui me manque est de savoir comment faire pour qu'un bouton dans la page du formulaire de changement exécute mon action d'administration personnalisée avec l'objet actuel.

Le but est de permettre à l'administrateur d'inspecter chaque objet individuellement et d'effectuer une action sur eux sans avoir besoin de revenir à la vue liste, de sélectionner l'objet inspecté et d'exécuter l'action à partir de la liste.

Mon action d'administration personnalisée ressemble à ceci:

def admin_apply_change(modeladmin, request, queryset):
    # loop over objects in query set and perform action

Je suppose qu'il existe un moyen simple et propre d'appeler cette action sous forme de changement d'administration, où le queryset ne contiendrait que l'objet actuellement ouvert que l'administrateur regarde.

REMARQUE: il serait préférable que le bouton soit en bas du formulaire de modification, à côté du bouton Save au lieu d'être en haut avec History qui n'est pas très visible.

Solution

Voir la réponse par Remi pour la solution. Pour que cela fonctionne, les corrections suivantes sont nécessaires:

1: Dans le remplacement de response_change l'initialisation de certaines variables est manquante:

opts = self.model._meta
pk_value = obj._get_pk_val()
preserved_filters = self.get_preserved_filters(request)

2: Nouvelle balise d'inclusion custom_submit_row doit être placé dans les templatetags et non dans l'administrateur (voir documents pour les templatetags personnalisés )

3: C'est le oubli que vous pourriez perdre un peu de temps. Dans change_form.html vous devez non seulement modifier la ligne suggérée:

{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}

mais aussi la ligne la plus importante en bas où submit_row apparaît:

{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

(il est situé juste au-dessus du bloc javascript dans change_form.html)

19
dsalaj

Vous pouvez jeter un œil à change_form_template et le définir sur un modèle personnalisé et remplacer le response_change méthode:

class MyModelAdmin(admin.ModelAdmin):

    # A template for a customized change view:
    change_form_template = 'path/to/your/custom_change_form.html'

    def response_change(self, request, obj):
        opts = self.model._meta
        pk_value = obj._get_pk_val()
        preserved_filters = self.get_preserved_filters(request)

        if "_customaction" in request.POST:
            # handle the action on your obj
            redirect_url = reverse('admin:%s_%s_change' %
                               (opts.app_label, opts.model_name),
                               args=(pk_value,),
                               current_app=self.admin_site.name)
             redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
             return HttpResponseRedirect(redirect_url)
        else:
             return super(MyModelAdmin, self).response_change(request, obj)

Copiez le change_form.html de ton site-packages/Django/contrib/admin/templates/change_form.html et éditez la ligne 44

 {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}

à

 {% if save_on_top %}{% block submit_buttons_top %}{% custom_submit_row %}{% endblock %}{% endif %}

Vérifiez également la ligne:

 {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

juste au-dessus du bloc javascript.

Ensuite, vous pouvez enregistrer une nouvelle balise d'inclusion quelque part dans votre admin.py ou l'ajouter à templatetags:

@register.inclusion_tag('path/to/your/custom_submit_line.html', takes_context=True)
def custom_submit_row(context):
    """
    Displays the row of buttons for delete and save.
    """
    opts = context['opts']
    change = context['change']
    is_popup = context['is_popup']
    save_as = context['save_as']
    ctx = {
        'opts': opts,
        'show_delete_link': (
            not is_popup and context['has_delete_permission'] and
            change and context.get('show_delete', True)
        ),
        'show_save_as_new': not is_popup and change and save_as,
        'show_save_and_add_another': (
            context['has_add_permission'] and not is_popup and
            (not save_as or context['add'])
        ),
        'show_save_and_continue': not is_popup and context['has_change_permission'],
        'is_popup': is_popup,
        'show_save': True,
        'preserved_filters': context.get('preserved_filters'),
    }
    if context.get('original') is not None:
        ctx['original'] = context['original']
    return ctx

Le contenu de votre custom_submit_line.html:

{% load i18n admin_urls %}
<div class="submit-row">
{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
{% if show_delete_link %}
    {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
    <p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p>
{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %}

<input type="submit" value="{% trans 'Custom Action' %}"  name="_customaction" />

</div>

C'est beaucoup de code, mais surtout du copier/coller. J'espère que cela pourra aider.

16
Remi Smirra

La plupart des gens le font probablement sans réfléchir, bien qu'il ne soit pas clair de la réponse que le formulaire de changement d'administrateur devrait être simplement étendu plutôt que complètement écrasé.

custom_change_form.html

{% extends "admin/change_form.html" %}

{% if save_on_top %}{% block submit_buttons_top %}{% custom_submit_row %}{% endblock %}{% endif %}

{% block submit_buttons_bottom %}{% custom_submit_row %}{% endblock %}
8
Andrew Bird

Alternativement, vous pouvez simplement étendre le fichier submit_line.html en ajoutant votre bouton personnalisé (à la fois en haut et en bas de la page de modification).

Votre fichier templates/adminyour_app_name/your_model_name.html commencera par:

{% extends "admin/submit_line.html" %}
{% load i18n admin_urls %}
<div class="submit-row">
  {% block submit-row %}  
     ... YOUR BUTTONS HERE ...
  {% endblock %}
</div>
1
Dos