Escrevendo comandos personalizados do django-admin

As aplicações podem registrar suas próprias ações com manage.py. Por exemplo, você pode querer adicionar uma ação manage.py para uma aplicação Django que você está distribuindo. Neste documento, construiremos um comando customizado closepoll para a aplicação polls do tutorial.

Pra tal, adicione um diretório management/commands a sua aplicação. O Django irá registrar um comando manage.py para cada módulo Python dentro deste diretório, cujo o nome não inicie com underscore. Por exemplo:

polls/
    __init__.py
    models.py
    management/
        commands/
            _private.py
            closepoll.py
    tests.py
    views.py

Neste exemplo, o comando closepoll estará disponível a qualquer projeto que inclua a aplicação polls em INSTALLED_APPS.

O módulo _private.py não estará disponível como um comando de gerenciamento.

O módulo closepoll.py tem apenas uma exigência – deve definir uma classe Command que estende BaseCommand ou uma de suas subclasses.

Scripts autônomos

Comandos de gerenciamento customizados, são especialmente úteis para a execução de scripts independentes ou para scripts que são periodicamente executados a partir do crontab do UNIX ou do painel de controle de tarefas agendadas do Windows.

Para implementar o comando, edite polls/management/commands/closepoll.py para que fique assim:

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 estiver usando comandos de gerenciamento e desejar enviar a saída para console, deve se escrever para o self.stdout e self.stderr, ao invés de imprimir para o stdout e stderr diretamente. Ao usar esses proxies, torna-se muito mais fácil para testar o seu comando personalizado. Observe também que você não precisa terminar mensagens com um caractere de nova linha, este será adicionado automaticamente, a menos que você especifique o parâmetro ending:

self.stdout.write("Unterminated line", ending='')

The new custom command can be called using python manage.py closepoll <poll_ids>.

O método handle() recebe um ou mais poll_ids e definie poll.opened como False para cada um. Se o usuário referenciar uma enquete inexistente, uma CommandError é gerada. O atributo poll.opened não existe no tutorial e foi adicionado ao polls.models.Question para este exemplo.

Aceitando argumentos opcionais

O mesmo closepoll poderia ser facilmente modificado para excluir uma determinada enquete, ao invés de fechá-la, aceitando as opções de linha de comando adicionais. Estas opções personalizadas podem ser adicionadas no método add_arguments() assim:

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

A opção (delete no nosso exemplo) está disponível no parâmetro dict (options) do método handle. Veja argparse na documentação do Python para saber mais sobre o uso do add_argument.

Além de ser capaz de adicionar opções personalizadas de linha de comando, todos comandos de gereciamento aceitam algumas opções padrão, tais como :opção:`--verbosity` e :opção:`--traceback`.

Comandos de gerenciamento e localidades

Por padrão, comandos de gerenciamento são executados com a localidade corrente ativa.

Se, por alguma razão, seu comando de gerenciamento personalizado precise ser executado sem um local ativo (por exemplo, para evitar que o conteúdo traduzido seja inserido dentro do banco de dados), desative a tradução utilizado o decorator @no_translations no seu método handle():

from django.core.management.base import BaseCommand, no_translations

class Command(BaseCommand):
    ...

    @no_translations
    def handle(self, *args, **options):
        ...

Como a desativação da tradução requer acesso as configurações definidas, os decorator’s não podem ser utilizados por comandos que trabalham sem configurações pré definidas.

Changed in Django 2.1:

O decorator “@no_translations” é novo. Em versões antigas, traduções eram desativadas antes de executar um comando, a menos que o atributo “leave_locale_alone” (descontinuado) esteja definido como “True”.

Testando

Informações sobre como testar comandos de gerenciamento personalizados pode ser encontradas na documentação de teste.

Sobrescrevendo comandos.

Django registra os comandos internos e depois procura os comandos em INSTALLED_APPS. Durante a busca, se for encontrado um comando que já tiver sido registrado, o comando encontrado substitui o primeiro.

Em outras palavras, para sobrescrever um comando, o novo comando precisa ter o mesmo nome e seu app precisa estar antes do comando da app a ser sobrescrito em : setting:INSTALLED_APPS.

Comando de gerenciamento de apps de terceiros que foram sobrescritos sem querer podem se tornar disponíveis sobre um novo nome pela criação de um novo comando em um dos apps do projeto (ordenado antes do app de terceiros em :setting:`INSTALLED_APPS) que importe o ‘Comando’ do comando sobrescrito.

Objetos Command

class BaseCommand[código fonte]

A classe base a partir da qual todos os comandos de gestão, em última análise derivam.

Use esta classe se você quer acesso a todos os mecanismos que realizam o parse dos argumentos da linha de comando e verificar qual código chamar em resposta; se você não precisa mudar este comportamento, considere usar uma dessas subclasses.

Subclasssing a classe BaseCommand requer que você implemente o método handle().

Atributos

Todos os atributos podem ser definidos em sua classe derivada e podem ser usados nas subclasses de BaseCommand

BaseCommand.help

Uma breve descrição do comando, que será impresso na mensagem de ajuda quando o usuário executar o comando python manage.py help <command>.

BaseCommand.missing_args_message

Se o seu comando define argumentos posicionais obrigatórios, você pode personalizar a mensagem de erro devolvida em caso de falta de argumentos. O padrão é a saída por argparse (“poucos argumentos”).

BaseCommand.output_transaction

Um booleano que indica como os comandos retornam SQL “statements”; Se True, a saída será automaticamente envolvido com BEGIN; e COMMIT;. O valor padrão é False.

BaseCommand.requires_migrations_checks

Um booleano; Se True, o comando “printa” um alerta se a definição das migrações no disco não estiver de acordo com as migrações no banco de dados. Um alerta não previne o comando de ser executado. O valor padrão é False.

BaseCommand.requires_system_checks

Um booleano; Se True, todo o projeto Django será verificado sobre potenciais problemas antes de executar o comando. O valor padrão é True.

BaseCommand.style

Um atributo de instância que ajuda a criar uma saída colorida quando se escreve no stdout ou stderr. Por exemplo:

self.stdout.write(self.style.SUCCESS('...'))

Veja sintaxe-coloring para aprender como modificar a paleta de cores e ver os estilos disponíveis (use caixa-alta das versões das opções descritas nessa seção).

Se você passar a opção --no-color ao executar o seu comando, todas as chamadas self.style() retornarão a string original sem colorir.

Métodos

BaseCommand tem alguns métodos que podem ser sobrescritos mas apenas o método handle() deve ser implementado.

Implementando um construtor em uma subclasse

Se você implementar __init__ em sua subclasse de BaseCommand, você deve chamar: o __init__ do class:` BaseCommand`:

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser(prog_name, subcommand, **kwargs)[código fonte]

Retorna uma instância de CommandParser, que é uma classe: argparse.ArgumentParser subclasse, com algumas personalizações para o Django.

Você pode customizar a instância por sobrecarga desse método, chamando super() com kwargs da classe:~argparse.ArgumentParser como parâmetro.

Changed in Django 2.2:

kwargs foi incluído.

BaseCommand.add_arguments(parser)[código fonte]

Ponto de entrada que recebe argumentos do “parser” para manipular comandos passados pela linha de comando. Comandos personalizados devem sobrescrever este método para adicionar ambos argumentos posicionais ou opicionais que sejam aceitos pelo comando. Não é necessário chamar o super() quando for uma subclasse de BaseCommand.

BaseCommand.get_version()[código fonte]

Retorna a versão do Django, que deve estar correto para todos os comandos internos do Django. É possível sobrescrever este método para que comandos fornecidos pelo usuário possam retornar a sua própria versão.

BaseCommand.execute(*args, **options)[código fonte]

Tenta executar este comando, realizando verificações de sistemas se necessário (como controlado pelo atributo requires_system_checks). Se o comando gerar um CommandError, este é interceptado e impresso no stderr.

Chamando um comando de gestão dentro do seu código

execute() não deve ser chamado diretamente do seu código para executar um comando. Ao invés disso, use call_command() .

BaseCommand.handle(*args, **options)[código fonte]

A lógica atual do comando. Subclasses devem implementar este método.

Pode retornar uma string tal qual será impressa no “stdout” (acrescido por “BEGIN;” e “COMMIT;” se :attr:’output_transaction’ for “True”).

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)[código fonte]

Usa a estrutura de verificação do sistema para inspecionar todo o projeto Django para os potenciais problemas. Graves problemas são levantados como CommandError; avisos são enviados para stderr; notificações menos importantes são enviados para stdout.

Se ambos app_configs e tags forem None, todas as verificações do sistema são realizadas. `` Tags`` pode ser uma lista tags de checagem, como compatibility ou models.

Subclasses de BaseCommand

class AppCommand

Um comando de gestão que recebe como argumento um ou mais “labels” de aplicações instaladas, e faz alguma coisa com cada um deles.

Melhor que implementar handle(), as subclasses devem implementar :meth:` ~AppCommand.handle_app_config`, que será chamado uma vez para cada aplicação.

AppCommand.handle_app_config(app_config, **options)

Executar ações do comando para app_config, o qual será uma instância de AppConfig correspondente a um label do aplicativo informado na linha de comando.

class LabelCommand

Um comando de gestão que recebe um ou mais argumentos arbitrários (“labels”) na linha de comando, e faz alguma coisa com cada um deles.

Em vez de implementar handle(), subclasses devem implementar handle_label(), que será chamado uma vez para cada etiqueta.

LabelCommand.label

Uma string que descreve os argumentos arbitrários passados para o comando. A string é usada no texto de uso e mensagens de erro do comando. Padrão para `` ‘label’``.

LabelCommand.handle_label(label, **options)

Executar ações do comando para label, que será a string como informada na linha de comando.

Exceções de comando

exception CommandError[código fonte]

A classe de exceção indica um problema ao executar um comando de gestão.

Se esta exceção é gerada durante a execução de um comando de gerenciamento chamado do console da linha de comando, ele será capturado e transformado em uma mensagem de erro devidamente impresso para a saída apropriada (isto é, stderr); como resultado, gerar essa exceção (com uma descrição sensata do erro) é a maneira preferida para indicar que algo deu errado na execução de um comando.

Se um comando de gestão é chamado do código através do call_command(), cabe a você capturar a exceção quando necessário.

Back to Top