カスタムdjango-adminコマンドの作成—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/howto/custom-management-commands
移動先:案内検索

カスタムdjango-adminコマンドの作成

アプリケーションは、manage.pyに独自のアクションを登録できます。 たとえば、配布しているDjangoアプリにmanage.pyアクションを追加したい場合があります。 このドキュメントでは、チュートリアルからpollsアプリケーション用のカスタムclosepollコマンドを作成します。

これを行うには、management/commandsディレクトリをアプリケーションに追加します。 Djangoは、名前がアンダースコアで始まらないディレクトリ内のPythonモジュールごとにmanage.pyコマンドを登録します。 例えば:

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

この例では、closepollコマンドは、:setting: `INSTALLED_APPS`pollsアプリケーションを含むすべてのプロジェクトで使用できるようになります。

_private.pyモジュールは管理コマンドとして使用できません。

closepoll.pyモジュールの要件は1つだけです。つまり、 BaseCommand またはそのサブクラスの1つを拡張するクラスCommandを定義する必要があります。

スタンドアロンスクリプト

カスタム管理コマンドは、スタンドアロンスクリプトの実行、またはUNIXcrontabまたはWindowsのスケジュールされたタスクのコントロールパネルから定期的に実行されるスクリプトに特に役立ちます。


コマンドを実装するには、polls/management/commands/closepoll.pyを次のように編集します。

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))

ノート

管理コマンドを使用していて、コンソール出力を提供したい場合は、stdoutおよびstderrに直接印刷するのではなく、self.stdoutおよびself.stderrに書き込む必要があります。 これらのプロキシを使用すると、カスタムコマンドのテストがはるかに簡単になります。 endingパラメータを指定しない限り、メッセージを改行文字で終了する必要はなく、自動的に追加されることにも注意してください。

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

新しいカスタムコマンドは、python manage.py closepoll <poll_ids>を使用して呼び出すことができます。

handle()メソッドは、1つ以上のpoll_idsを取り、それぞれに対してpoll.openedFalseに設定します。 ユーザーが存在しないポーリングを参照した場合、 CommandError が発生します。 poll.opened属性はチュートリアルに存在せず、この例ではpolls.models.Questionに追加されました。

オプションの引数を受け入れる

同じclosepollを簡単に変更して、追加のコマンドラインオプションを受け入れることで特定のポーリングを閉じる代わりに削除することができます。 これらのカスタムオプションは、次のように add_arguments()メソッドに追加できます。

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

オプション(この例ではdelete)は、handleメソッドのoptionsdictパラメーターで使用できます。 add_argumentの使用法の詳細については、argparse Pythonのドキュメントを参照してください。

カスタムコマンドラインオプションを追加できることに加えて、すべての管理コマンドは、--verbosity--tracebackなどのいくつかのデフォルトオプションを受け入れることができます。


管理コマンドとロケール

デフォルトでは、管理コマンドは現在アクティブなロケールで実行されます。

何らかの理由で、カスタム管理コマンドをアクティブなロケールなしで実行する必要がある場合(たとえば、翻訳されたコンテンツがデータベースに挿入されないようにするため)、ハンドルの@no_translationsデコレータを使用して翻訳を非アクティブ化します。 )メソッド:

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

class Command(BaseCommand):
    ...

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

翻訳の非アクティブ化には構成済みの設定へのアクセスが必要なため、構成済みの設定なしで機能するコマンドにデコレータを使用することはできません。


テスト

カスタム管理コマンドのテスト方法に関する情報は、テストドキュメントにあります。


コマンドのオーバーライド

Djangoは組み込みコマンドを登録し、:setting: `INSTALLED_APPS` でコマンドを逆に検索します。 検索中に、コマンド名がすでに登録されているコマンドと重複している場合、新しく検出されたコマンドが最初のコマンドをオーバーライドします。

つまり、コマンドをオーバーライドするには、新しいコマンドの名前が同じであり、そのアプリが:setting: `INSTALLED_APPS` でオーバーライドされたコマンドのアプリの前にある必要があります。

意図せずにオーバーライドされたサードパーティアプリの管理コマンドは、プロジェクトのアプリの1つで新しいコマンドを作成することで新しい名前で利用できるようになります(:setting: `INSTALLED_APPS` [でサードパーティアプリの前に注文] X247X])オーバーライドされたコマンドのCommandをインポートします。


コマンドオブジェクト

class BaseCommand

すべての管理コマンドが最終的に派生する基本クラス。

コマンドライン引数を解析し、それに応じて呼び出すコードを計算するすべてのメカニズムにアクセスする場合は、このクラスを使用します。 その動作を変更する必要がない場合は、そのサブクラスのいずれかを使用することを検討してください。

BaseCommand クラスをサブクラス化するには、 handle()メソッドを実装する必要があります。

属性

すべての属性は派生クラスで設定でき、 BaseCommandサブクラスで使用できます。

BaseCommand.help
コマンドの簡単な説明。ユーザーがコマンドpython manage.py help <command>を実行するとヘルプメッセージに出力されます。
BaseCommand.missing_args_message
コマンドで必須の位置引数が定義されている場合は、引数が欠落している場合に返されるメッセージエラーをカスタマイズできます。 デフォルトはargparse(「引数が少なすぎる」)によって出力されます。
BaseCommand.output_transaction
コマンドがSQLステートメントを出力するかどうかを示すブール値。 Trueの場合、出力は自動的にBEGIN;COMMIT;でラップされます。 デフォルト値はFalseです。
BaseCommand.requires_migrations_checks
ブール値; Trueの場合、ディスク上の移行のセットがデータベース内の移行と一致しない場合、コマンドは警告を出力します。 警告は、コマンドの実行を妨げるものではありません。 デフォルト値はFalseです。
BaseCommand.requires_system_checks

タグのリストまたはタプル。例: [Tags.staticfiles, Tags.models]。 選択したタグに登録されているシステムチェックは、コマンドを実行する前にエラーがチェックされます。 値'__all__'を使用して、すべてのシステムチェックを実行する必要があることを指定できます。 デフォルト値は'__all__'です。

バージョン3.2で変更:古いバージョンでは、requires_system_checks属性は、タグのリストまたはタプルではなくブール値を予期していました。

BaseCommand.style

stdoutまたはstderrに書き込むときに色付きの出力を作成するのに役立つインスタンス属性。 例えば:

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

カラーパレットを変更する方法と使用可能なスタイルを確認するには、構文の色付けを参照してください(このセクションで説明されている「ロール」の大文字バージョンを使用してください)。

コマンドの実行時に--no-colorオプションを渡すと、すべてのself.style()呼び出しは色なしの元の文字列を返します。


メソッド

BaseCommand には、オーバーライドできるメソッドがいくつかありますが、実装する必要があるのは handle()メソッドのみです。

サブクラスでのコンストラクターの実装

BaseCommand のサブクラスに__init__を実装する場合は、 BaseCommand__init__を呼び出す必要があります。

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser(prog_name, subcommand, **kwargs)

CommandParserインスタンスを返します。これは、Django用にいくつかカスタマイズされたArgumentParserサブクラスです。

このメソッドをオーバーライドし、ArgumentParserパラメーターのkwargsを指定してsuper()を呼び出すことにより、インスタンスをカスタマイズできます。

BaseCommand.add_arguments(parser)
コマンドに渡されるコマンドライン引数を処理するためのパーサー引数を追加するためのエントリポイント。 カスタムコマンドは、このメソッドをオーバーライドして、コマンドで受け入れられる定位置引数とオプション引数の両方を追加する必要があります。 BaseCommandを直接サブクラス化する場合、super()を呼び出す必要はありません。
BaseCommand.get_version()
Djangoのバージョンを返します。これは、すべての組み込みDjangoコマンドに対して正しいはずです。 ユーザー指定のコマンドは、このメソッドをオーバーライドして、独自のバージョンを返すことができます。
BaseCommand.execute(*args, **options)
このコマンドの実行を試み、必要に応じてシステムチェックを実行します( require_system_checks 属性によって制御されます)。 コマンドが CommandError を発生させた場合、それは傍受されてstderrに出力されます。

コードで管理コマンドを呼び出す

execute()は、コマンドを実行するためにコードから直接呼び出さないでください。 代わりに call_command()を使用してください。


BaseCommand.handle(*args, **options)

コマンドの実際のロジック。 サブクラスはこのメソッドを実装する必要があります。

stdoutに出力される文字列を返す場合があります( output_transactionTrueの場合、BEGIN;COMMIT;でラップされます)。

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)

システムチェックフレームワークを使用して、潜在的な問題についてDjangoプロジェクト全体を検査します。 深刻な問題は CommandError として発生します。 警告はstderrに出力されます。 マイナー通知がstdoutに出力されます。

app_configstagsが両方ともNoneの場合、すべてのシステムチェックが実行されます。 tagsは、compatibilitymodelsなどのチェックタグのリストにすることができます。


BaseCommandサブクラス

class AppCommand

インストールされている1つ以上のアプリケーションラベルを引数として受け取り、それぞれに対して何かを実行する管理コマンド。

サブクラスは、 handle()を実装するのではなく、 handle_app_config()を実装する必要があります。これは、アプリケーションごとに1回呼び出されます。

AppCommand.handle_app_config(app_config, **options)
app_configに対してコマンドのアクションを実行します。これは、コマンドラインで指定されたアプリケーションラベルに対応する AppConfig インスタンスになります。
class LabelCommand

コマンドラインで1つ以上の任意の引数(ラベル)を受け取り、それぞれに対して何かを行う管理コマンド。

サブクラスは、 handle()を実装するのではなく、 handle_label()を実装する必要があります。これは、ラベルごとに1回呼び出されます。

LabelCommand.label
コマンドに渡される任意の引数を説明する文字列。 この文字列は、コマンドの使用法テキストとエラーメッセージで使用されます。 デフォルトは'label'です。
LabelCommand.handle_label(label, **options)
labelに対してコマンドのアクションを実行します。これは、コマンドラインで指定された文字列になります。


コマンドの例外

exception CommandError(returncode=1)

管理コマンドの実行中に問題が発生したことを示す例外クラス。

コマンドラインコンソールからの管理コマンドの実行中にこの例外が発生した場合、この例外はキャッチされ、適切な出力ストリーム(つまり、stderr)に適切に出力されたエラーメッセージに変換されます。 結果として、この例外を(エラーの適切な説明とともに)発生させることは、コマンドの実行で問題が発生したことを示すための好ましい方法です。 オプションのreturncode引数を受け入れ、sys.exit()を使用して、終了する管理コマンドの終了ステータスをカスタマイズします。

管理コマンドが call_command()を介してコードから呼び出された場合、必要に応じて例外をキャッチするのはあなた次第です。

バージョン3.1で変更: returncode引数が追加されました。