Come creare comandi django-admin
personalizzati¶
Le applicazioni possono registrare le proprie azioni con manage.py
. Per esempio, potresti voler aggiungere una azione manage.py
per una applicazione Django che stai distribuendo. In questo documento, costruiremo un comando personalizzato closepoll
per l’applicazione polls
dal tutorial.
To do this, add a management/commands
directory to the application. Django
will register a manage.py
command for each Python module in that directory
whose name doesn’t begin with an underscore. For example:
polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py
In questo esempio, il comando closepoll
sarà reso disponibile a qualsiasi progetto che includa l’applicazione polls
in INSTALLED_APPS
.
Il modulo _private.py
non sarà disponibile come comando di management.
Il modulo closepoll.py
ha un solo requisito – deve definire una classe Command
che estenda BaseCommand
o una delle sue sottoclassi.
Script standalone
Il comandi di management personalizzati sono utili soprattutto per lanciare script standalone o per script che sono eseguiti periodicamente con il crontab di UNIX o dal pannello di controllo per la pianificazione dei task di Windows.
Per implementare il comando, modifica polls/management/commands/closepoll.py
in questo modo :
from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll
class Command(BaseCommand):
help = "Closes the specified poll for voting"
def add_arguments(self, parser):
parser.add_argument("poll_ids", nargs="+", type=int)
def handle(self, *args, **options):
for poll_id in options["poll_ids"]:
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise CommandError('Poll "%s" does not exist' % poll_id)
poll.opened = False
poll.save()
self.stdout.write(
self.style.SUCCESS('Successfully closed poll "%s"' % poll_id)
)
Nota
Quando utilizzi i comandi di management personalizzati e vuoi ottenere dell’output su console, dovresti scrivere su self.stdout
e self.stderr
, invece che direttamente su stdout` and stderr
. Utilizzando questi proxy, diventa molto più facile testare il tuo comando personalizzato. Nota anache che non hai bisogno di terminare i messaggi con il carattere di newline, sarà aggiunto automaticamente, a meno che tu non specifichi il parametro ending
:
self.stdout.write("Unterminated line", ending="")
Il nuovo comando personalizzato potrà essere chiamato con python manage.py closepoll <poll_ids>
.
Il metodo handle()
prende uno o più poll_ids
ed imposta poll.opened
a False
per ognuno di essi. Se l’utente fa riferimento ad un poll non esistente, viene sollevato un CommandError
. L’attributo poll.opened
non esiste nel tutorial ed è stato aggiunto a polls.models.Question
per questo esempio.
Accetta argomenti opzionali¶
Lo stesso closepoll
può essere modificato facilmente per cancellare un dato poll invece che chiuderlo accettando opzioni sulla command line. Queste opzioni personalizzate possono essere aggiunte nel metodo add_arguments()
così:
class Command(BaseCommand):
def add_arguments(self, parser):
# Positional arguments
parser.add_argument("poll_ids", nargs="+", type=int)
# Named (optional) arguments
parser.add_argument(
"--delete",
action="store_true",
help="Delete poll instead of closing it",
)
def handle(self, *args, **options):
# ...
if options["delete"]:
poll.delete()
# ...
L’opzione (delete
nel nostro esempio) è disponibile nel dizionario di parametri delle opzioni del metodo handle. Vedi la documentazione di Python di argparse
per saperne di più sull’utilizzo di add_argument
.
Oltre ad essere in grado di aggiungere opzioni personalizzate per la command line, tutti i comandi di management possono accettare alcune opzioni di default come --verbosity
e --traceback
.
Commandi di gestione e traduzioni/locale¶
Di default, i comandi di management sono eseguiti con il locale che è correntemente attivo.
Se, per qualche ragione, il tuo comando di management personalizzato deve girare senza un locale attivo (per esempio, per evitare che il contenuto tradotto venga inserito nel database), disattiva le traduzioni usando il decoratore @no_translations
sul tuo metodo handle()
from django.core.management.base import BaseCommand, no_translations
class Command(BaseCommand):
...
@no_translations
def handle(self, *args, **options):
...
Dal momento che la disattivazione della traduzione richiede l’accesso alle impostazioni di configurazione, il decoratore non può essere usato per comandi che funzionino senza impostazioni di configurazione.
Testing¶
Informazioni su come testare i comandi di management personalizzati possono essere trovate nei documenti di testing.
Override dei comandi¶
Django registra i comandi built-in e poi cerca comandi in INSTALLED_APPS
in senso inverso. Durante la ricerca, se un nome di comando duplica un comando già registrato, fa override su quello precedente.
In altre parole, per fare override di un comando, il nuovo comando deve avere lo stesso nome e la sua app deve trovarsi prima di quella del comando su cui fare override in INSTALLED_APPS
.
I comandi di management di app di terze parti che sono stati sovrascritti in modo non intenzionale posso essere resi disponibili con un nuovo nome creando un nuovo comando in una delle app del tuo progetto (che si trovi in ordine prima dell’app di terze parti in INSTALLED_APPS
) che importi il Command
del comando sovrascritto.
Oggetti Command¶
-
class
BaseCommand
¶
La classe di base da cui, in ultima analisi, tutti i comandi di management derivano.
Usa questa classe se vuoi accedere a tutti i meccanismi che fanno parsing degli argomenti di command-line e cercano di capire quale codice chiamare in risposta; se non hai bisogno di cambiare questo comportamento, considera di usare una delle sue sottoclassi.
Fare una sottoclasse della classe BaseCommand
ti richiede di implementare il metodo handle()
.
Attributi¶
Tutti gli attributi possono essere impostati nella tua classe derivata e possono essere usati nelle sottoclassi di BaseCommand
.
-
BaseCommand.
help
¶ Una breve descrizione del comando, che sarà stampata nel messaggio di aiuto quando l’utente lancia il comando
python manage.py help <command>
.
-
BaseCommand.
missing_args_message
¶ Se il tuo comando definisce degli argomenti posizionali obbligatori, puoi personalizzare il messaggio di errore restituito in caso di argomenti mancanti. Quello di default è restituito da
argparse
(«too few arguments»).
-
BaseCommand.
output_transaction
¶ Un booleano che indica se il comando mostra in output uno statement SQL; se
True
, l’output sarà automaticamente inserito traBEGIN;
eCOMMIT;
. Il valore predefinito èFalse
.
-
BaseCommand.
requires_migrations_checks
¶ Un booleano; se
True
, il comando stampa un messaggio di warning se il set di migrazioni su disco non corrisponde a quelle sul database. Un warning non impedisce l’esecuzione del comando. Il valore predefinito èFalse
.
-
BaseCommand.
requires_system_checks
¶ Un lista di tuple di tag, per esempio
[Tags.staticfiles, Tags.models]
. Il sistema controlla che la registrazione nei tag scelti sia sottoposta a controllo di errori prima di eseguire il comando. Il valore'__all__'
può essere usato per specificare che tutti i controlli siano eseguiti. Il valore predefinito è'__all__'
.
-
BaseCommand.
style
¶ Un attributo di istanza che aiuta a creare output colorato quando si scrive su
stdout
ostderr
. Per esempio:self.stdout.write(self.style.SUCCESS("..."))
Vedi Syntax coloring per imparare come modificare la palette di colori e visualizzare gli stili disponibili (usa le versioni maiuscole dei «ruoli» descritti in quella sezione).
Se passi l’opzione
--no-color
quando lanci il comando, tutte le chiamateself.style()
restituiranno la stringa originale senza colori.
-
BaseCommand.
suppressed_base_arguments
¶ Le opzioni dei comandi di default da sopprimere nell’output dell’help. Dovrebbe essere un set di nomi di opzione (per es.
'--verbosity'
). I valori di default per tutte le opzioni soppresse vengono comunque passati.
Metodi¶
La classe BaseCommand
ha pochi metodi che possono essere sovrascritti ma solo il metodo handle()
deve essere implementato.
Implementazione di un constructor in una subclasse
Se implementi __init__
nella tua sottoclasse di BaseCommand
, devi chiamare __init__
di BaseCommand
:
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ...
-
BaseCommand.
create_parser
(prog_name, subcommand, **kwargs)¶ Restituisce una istanza di
CommandParser
, che è una sottoclasse diArgumentParser
con qualche personalizzazione per Django.Puoi personalizzare l’istanza sovrascrivendo questo metodo e chiamando
super()
con parametrikwargs
ArgumentParser
.
-
BaseCommand.
add_arguments
(parser)¶ L’entry point per aggiungere argomenti del parser per gestire gli argomenti della command line passati al comando. I comandi personalizzati dovrebbero sovrascrivere questo metodo per aggiungere sia argomenti facoltativi che posizionali che siano accettati dal comando. Non è necessario chiamare
super()
quando si utilizza una sottoclasse diBaseCommand
.
-
BaseCommand.
get_version
()¶ Restituisce la versione di Django, che dovrebbe essere corretta per tutti i comandi Django built-in. I comandi forniti dall’utente possono sovrascrivere questo metodo per restituire la propria versione.
-
BaseCommand.
execute
(*args, **options)¶ Cerca di eseguire questo comando, facendo i controlli di sistema se necessario (come controllato con l’attributo
requires_system_checks
). Se il comando sollevaCommandError
, questo viene intercettato e stampato sustderr
.
Chiamata di un commando di ?gestione? nel tuo codice
execute()` non dovrebbe essere chiamato direttamente dal tuo codice per eseguire un comando. Usa invece call_command()
.
-
BaseCommand.
handle
(*args, **options)¶ La logica attuale del comando. Le sottoclassi devono implementare questo metodo
Può restituire una stringa che sarà stampata su
stdout
(traBEGIN;
eCOMMIT;
seoutput_transaction
èTrue
).
-
BaseCommand.
check
(app_configs=None, tags=None, display_num_errors=False)¶ Usa il framework di controlli di sistema per ispezionare l’intero progetto Django in cerca di potenziali problemi. I problemi gravi sono segnalati cpme
CommandError
; i warning sono stampati sustderr
; le notifiche minori sono stampate sustdout
.Se
app_configs
etags
sono entrambiNone
, sono effettuati tutti i controlli di sistema.tags
può essere una lista di tag di controllo, comecompatibility
omodels
.
sottoclassi BaseCommand
¶
-
class
AppCommand
¶
Un comando di gestione che accetta una o più etichette di applicazioni installate come argomenti e fa qualcosa con ciascuna di esse.
Piuttosto che implementare handle()
, le sottoclassi devono implementare handle_app_config()
, che sarà chiamata una volta per ogni applicazione.
-
AppCommand.
handle_app_config
(app_config, **options)¶ Effettua le azioni del comando per
app_config
, che sarà una istanza diAppConfig
corrispondente ad una etichetta di applicazione fornita sulla linea di comando.
-
class
LabelCommand
¶
Un comando di gestione che accetta uno o più argomenti arbitrari (etichette) dalla linea di comando e fa qualcosa con ciascuno di essi.
Piuttosto che implementare handle()
, le sottoclassi devono implmentare handle_label()
, che sarà chiamato una volta per ogni etichetta.
-
LabelCommand.
label
¶ Una stringa che descrive gli argomenti arbitrari forniti al comando. La stringa viene usata nel testo di utilizzo e nei messaggi di errore del comando. Di default è pari a
'label'
.
-
LabelCommand.
handle_label
(label, **options)¶ Effettua le azioni del comando per
label
, che sarà la stringa come è fornita dalla riga di comando.
Eccezioni di comando¶
-
exception
CommandError
(returncode=1)¶
Una classe di eccezione che indica un problema mentre si esegue un comando di gestione.
Se questa eccezione viene sollevata durante l’esecuzione di un comando di management da una console a linea di comando, sarà gestito e trasformato in un messaggio di errore stampato in modo gradevole verso lo stream di output appropriato (per es. stderr
); di conseguenza, sollevare questa eccezione (con una descrizione sensibile dell’errore) è la modalità preferita di indicare che qualcosa è andato storto durante l’esecuzione di un comando. Essa accetta l’argomento opzionale returncode
per personalizzare l’exit status del comando di management, usando sys.exit()
.
Se il comando di gestione è chiamato dal codice con call_command()
, è tuo compito catturare l’eccezione quando è necessario.