Creazione ed utilizzo delle Custom Actions in Django Admin

Ti è mai capitato di dover eseguire la medesima operazione su più elementi di un elenco all'interno del backoffice? Hai mai avuto la necessità di aggiornare lo status degli ordini sul tuo ecommerce massivamente? Hai mai avuto la necessità di rimuovere con un solo click elementi multipli?

Se la tua risposta alle precedenti domande è affermativa, sai benissimo che effettuare tali operazioni da backoffice, ripetendola singolarmente su ogni elemento, è un'operazione noiosa, lunga, e può facilmente portare ed errore umano. Sai che se l'operazione è di cancellazione, un errore potrebbe essere veramente grave e portarci via tantissimo tempo per ripristinare la situazione.

L'aggiornamento manuale è una strada assolutamente sconsigliabile a chiunque voglia fare le cose per bene senza incorrere in errori o problemi.

Un'alternativa all'aggiornamento manuale, potrebbe essere l'aggiornamento dei dati lavorando direttamente con il database applicativo. Questo approccio, tuttavia, ha molte controindicazioni: non sempre abbiamo accesso al database, devi conoscere l'SQL per eseguire le operazioni, un errore potrebbe seriamente compromettere il nostro applicativo. Sebbene l'approccio è sicuramente migliorativo rispetto all'aggiornamento manuale, non rappresenta una strada sempre percorribile.

Come terza possibilità, puoi utilizzare uno strumento offerto dal framework Django all'interno dell'applicazione Django Admin.

Django Admin consente di eseguire operazioni massive su più elementi attraverso l'implementazione delle custom actions. Ogni custom action esegue l'operazione implementata dallo sviluppatore sugli elementi selezionati del backoffice. Quindi potrai inserire l'operazione massiva desiderata (aggiornamento status, cancellazione elementi, modifica importo) ed applicarla dinamicamente sugli elementi che selezioni dal backoffice Django Admin.

In questo articolo vedrai come implementare una custom action su un campo status che contiene al suo interno delle etichette di stato (choices). La custom action modifica la proprietà status del modello Calciatore da svincolato a contrattualizzato.

Creazione nel ModelAdmin

Puoi associare Una custom action ad un ModelAdmin, inserendo il nome dell'azione all'interno della lista actions del ModelAdmin sul quale vorrai far comparire l'azione. Le azioni possono essere implementate sia all'interno di funzioni sia come metodo di una classe.

Azione come funzione

Per aggiungere un'azione come funzione, inserirai l'elemento all'interno della lista come chiamata a funzione.

Il seguente frammento di codice mostra un esempio di definizione di custom action come funzione:

# implementazione della custom action come funzione
def nome_azione(modeladmin, request, queryset):
    pass

@admin.register(Prodotto)
class ProdottoAdmin(admin.ModelAdmin):
    actions = [nome_azione]

Azione come classe

Per aggiungere un'azione come metodo di una classe, l'inserimento all'interno della lista actions avviene indicando il nome del metodo all'interno di una stringa.

Il seguente frammento di codice mostra come definire un'azione come metodo di una classe:

class ProdottoMixin:
    def nome_azione(self, request, queryset):
        pass

@admin.register(Prodotto)
class ProdottoAdmin(admin.ModelAdmin):
    actions = ['nome_azione']

Creazione come funzione

Implementare la custom action come funzione consente di rendere trasversale ai modelli l'implementazione. Per creare tale funzione, all'interno del file admin.py, dovrai inserire l'implementazione di una funzione che preveda i seguenti parametri:

  • modeladmin: rappresenta il ModelAdmin considerato;
  • request: request generica con la quale si è richiesta la pagina di backoffice;
  • queryset: insieme di elementi sui quali eseguire l'azione

Il codice inserito all'interno della funzione effettua delle modifiche sugli elementi selezionati sul backoffice.

Facendo un esempio, selezionando gli elementi presenti nella lista sul backoffice ed eseguendo il codice presente all'interno della funzione contrattualizza, sarà modificato lo status dei calciatori da svincolato a con_contratto.

Il codice implementato all'interno della funzione è il seguente:

def contrattualizza(modeladmin, request, queryset):
    num_items = queryset.update(status=Calciatore.CON_CONTRATTO)
    modeladmin.message_user(
        request,
        f"Contrattualizzati {num_items} calciatori.",
        messages.SUCCESS
    )

All'interno della funzione è presente anche la chiamata al message_user del modeladmin che consente l'inserimento della barra di successo nella quale sono proposti all'utente dei messaggi sull'esito dell'operazione effettuata.

Come puoi evincere dal codice, la funzione esegue un update dello status portandolo al valore CON_CONTRATTO; l'aggiornamento è eseguito sul queryset selezionato dal backoffice Django.

Creazione come metodo di classe

Implementare la custom action come metodo di una classe consente di utilizzare l'azione solamente estendendo la classe all'interno del ModelAdmin. I parametri di input sono allineati con quelli che sono inseriti all'interno dell'azione implementata come funzione.

Proponendo un esempio, considerando la classe ContrattualizzaMixin possiamo implementare la funzione contrattualizza_calciatore per creare l'azione.

class ContrattualizzaMixin:
    def contrattualizza_calciatore(self, request, queryset):
        num_items = queryset.update(status=Calciatore.CON_CONTRATTO)
        self.message_user(
            request,
            f"Contrattualizzati {num_items} calciatori.",
            messages.SUCCESS
        )

Per inserire l'azione all'interno del ModelAdmin inserire il seguente codice:

class CalciatoreAdmin(admin.ModelAdmin, ContrattualizzaMixin):
    actions = ['contrattualizza_calciatore']

Rinominare l'azione

Entrambe le soluzioni proposte, sia nell'implementazione come funzione che come metodo di classe, prevedono la possibilità di rinominare l'azione all'interno del pannello di amministrazione di Django Admin.

Per rinominare l'azione, valorizzare la proprietà short_description come segue:

# implementazione come funzione
def nome_azione(...):
    pass
nome_azione.short_description = 'Nuovo nome azione'

# implementazione come metodo di classe
class ProdottoMixin:
    def nome_azione(...):
        pass
    nome_azione.short_description = 'Nuovo nome azione'

All'interno del backoffice Django appare a questo punto la short_description definita e non più il nome della funzione o del metodo.

Conclusioni

Gli esempi mostrano come creare una custom action all'interno del pannello di amministrazione di Django Admin sia come funzione che come metodo di classe.

L'articolo mostra come aggiornare lo status di un modello calciatore, applicando le modifiche solo alle istanze selezionate dall'utente sul backoffice.