# Documentazione Django 6.0.7

# 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()
            # ...

The option (`delete` in our example) is available in the options dict parameter of the handle method. See the `argparse` Python documentation for more about `add_argument` usage.

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

  If your command defines mandatory positional arguments, you can customize the message error returned in the case of missing arguments. The default is output by `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 tra `BEGIN;` e `COMMIT;`. 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` o `stderr`. 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 chiamate `self.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 di `ArgumentParser` con qualche personalizzazione per Django.

  Puoi personalizzare l’istanza sovrascrivendo questo metodo e chiamando `super()` con parametri `kwargs` `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 di `BaseCommand`.

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 solleva `CommandError`, questo viene intercettato e stampato su `stderr`.

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` (tra `BEGIN;` e `COMMIT;` se `output_transaction` è `True`).

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False, include_deployment_checks=False, fail_level=checks.ERROR, databases=None)

  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 su `stderr`; le notifiche minori sono stampate su `stdout`.

  If `app_configs` and `tags` are both `None`, all system checks are performed except deployment and database related checks. `tags` can be a list of check tags, like `compatibility` or `models`.

  You can pass `include_deployment_checks=True` to also perform deployment checks, and list of database aliases in the `databases` to run database related checks against them.

BaseCommand.get_check_kwargs(options)

  Supplies kwargs for the call to `check()`, including transforming the value of `requires_system_checks` to the `tag` kwarg.

  Override this method to change the values supplied to `check()`. For example, to opt into database related checks you can override `get_check_kwargs()` as follows:

      def get_check_kwargs(self, options):
          kwargs = super().get_check_kwargs(options)
          return {**kwargs, "databases": [options["database"]]}

### 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 di `AppConfig` 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.