💭

[Django]カスタムコマンドを作る

2021/05/04に公開

カスタムコマンド

Djangoでは、コマンドを自作することができます。
例えば、こんな感じに。

$ python manage.py mycommand

使いどころ

例えば、Djangoアプリの中で、バッチスクリプトを定義して、それだけ以下のように実行もできます。

$ python app/batch.py

が、Djangoが提供する機能を100%使えないので、カスタムコマンドを作るのがいちばんいいと思います。(例えば通常のスクリプトで書く場合、modelなどが活用できません)

作ってみる

やることリスト

おおよそ以下の手順で作っていきます。

  • startappで「sample_app」アプリを作る
  • settings.pyのINSTALLED_APPSに追加
  • 「sample_app」直下に「management」フォルダを作る
  • 「management」の中に「commands」フォルダを作る
  • 「commands」の中に「__init__.py」を作る
  • 「commands」の中に「mycommand.py」を作る
  • mycommand.py」にdjango.core.management.base.BaseCommandを継承したCommandクラスを作り、必要なメソッドをオーバーライドする
  • 「python manage.py mycommand」とすると定義したプログラムを実行できる

準備

とりあえずDjangoプロジェクトから作ってみましょう。
Linuxコマンドでフォルダやファイル作ってますけど、コマンドじゃなくても一緒です。

$ django-admin startproject project
$ cd project
$ python startapp sample_app
$ mkdir -p sample_app/management/commands
$ touch sample_app/management/commands/__init__.py
$ touch sample_app/management/commands/mycommand.py
INSTALLED_APPS = [
    ...
    'sample_app.apps.SampleAppConfig'
]
tree
.
├── sample_app
│   ├── 省略
│   ├── management
│   │   └── commands
│   │       ├── __init__.py
│   │       └── mycommand.py
├── manage.py
└── project

こんなフォルダ構造になっていればOKです。

コマンドファイルを書いていく

from django.core.management.base import BaseCommand


class Command(BaseCommand):
    help = "テストコマンド"

    def handle(self, *args, **options):
        print('Hello World!')

ポイントは、

  • BaseCommandを継承したCommandを定義すること
  • Commandクラスの変数helpはpython manage.py help カスタムコマンド名としたときに表示される説明文的なもの
  • handleメソッドを継承すること
    • handleメソッド内に実行した処理を書く

実行してみる

もう実行できます。

$ python manage.py mycommand
Hello
$ python manage.py help mycommand
usage: manage.py mycommand [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback]
                           [--no-color] [--force-color] [--skip-checks]

テストコマンド

optional arguments:
  -h, --help            show this help message and exit
省略

意外と簡単でしたね。

【発展】コマンドライン引数を定義する

add_argumentsメソッドを書き加える

Commandクラスのadd_argumentsメソッドを加えると、コマンドライン引数を定義することができます。

class Command(BaseCommand):
    help = "テストコマンド"

    def handle(self, *args, **options):
        print('Hello ' + options['name'])

    def add_arguments(self, parser):
        parser.add_argument('--name', nargs='?', default='', type=str)

ポイントは、add_argumentのキーワード引数です(デフォルト引数?)。

引数名 意味
第一引数 コマンドライン引数名、オプション名
nargs コマンドライン引数の長さ。1つのキーワードに対して複数与えたりできる ?や+,1,2などの数の指定ができる。
default 引数に与えなかった場合の初期値を示す。
type strとかintとか型を指定する
そのほか にもたくさんあります。

handleメソッドで使う時は、引数optionsから取り出しましょう。

実行してみる

$ python manage.py mycommand
Hello
$ python manage.py mycommand --name zenn
Hello zenn

参考

https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/

https://docs.python.org/ja/3/library/argparse.html#the-add-argument-method

Discussion