Djangoでカスタムコマンドを作成する

背景

Djangoでバッチを実行することになりました。

Railsの場合はRakeタスクがあります。Djangoの場合はどのように行うのか調べて試してみました。

既存のカスタムコマンドの確認

Djangoでコマンドを追加するには、manage.pyを使ったカスタムコマンドと呼ばれる処理を追加することになります。もともとDjangoにはmanage.pyを利用したコマンドがいくつもあります。一覧で見てみましょう。一覧で見るにはmanage.pyに引数をつけずに実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
$ docker-compose run --rm web python manage.py
Starting django_db_1 ... done
Creating django_web_run ... done

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
changepassword
createsuperuser

[contenttypes]
remove_stale_contenttypes

[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver

[sessions]
clearsessions

[staticfiles]
collectstatic
findstatic
runserver

runserverstartprojectなど見慣れたコマンドもいくつかありますが、ほとんど知らないコマンドです。こんなにあるんですね。

[]で囲まれているのはアプリケーション名でしょうか。settings.pyINSTALLED_APPSに指定されている名前と一致しています。

カスタムコマンドを追加する

カスタムコマンドの追加方法はこちらに記載されています。正確にはカスタムマネジメントコマンドなんですね。

実行ファイルを配置する

先ほどの公式サイトには以下のようにディレクトリ階層が書かれています。

1
2
3
4
5
6
7
8
9
10
11
polls/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
closepoll.py
tests.py
views.py

ですので、アプリケーションディレクトリの下にmanagementディレクトリを作成し、その下にcommandsディレクトリを作成して、その下に実行するファイルを置く感じのようです。

実際に作成してみます。

1
2
3
$ cd sample_application
$ mkdir -p management/commands/
$ touch management/commands/dummy.py

これで実行ファイルを配置することができました。

実行ファイルを実装する

カスタムコマンドの実行方法についても、先ほどの公式サイトに記載されています。

例ではBaseCommandCommandErrorをimportしていますが動かすだけであればBaseCommandのみでよさそうです。今回は単純なサンプルを作って実行できるところまで試したいので、BaseCommandのみ利用したいと思います。

(タスクが正常に動作しなかった場合はCommandError例外をあげて知らせるということだと思います)

ということで、dummy.pyを実装してみました

1
2
3
4
5
6
7
8
9
10
from django.core.management.base import BaseCommand

class Command(BaseCommand):
help = 'Dummy command'

def add_arguments(self, parser):
pass

def handle(self, *args, **options):
print("execute Dummy command")

では実行してみます。

カスタムコマンドを実行する

それでは実行してみましょう。

1
2
3
4
$ docker-compose run --rm web python manage.py dummy
Creating django_web_run ... done
Unknown command: 'dummy'
Type 'manage.py help' for usage.

おっと、実行に失敗してしまいました…どこか設定が足りないようなので、調べてみます。

INSTALLED_APPへの追加

どの設定が足りないのかを調べていたところ、公式サイトにあまり目立たない感じで以下のように書かれていました。

1
In this example, the closepoll command will be made available to any project that includes the polls application in INSTALLED_APPS.

この例の場合は、pollsINSTALLED_APPSに設定すると有効になります、的なことが書いてあるのかと思います。

ということでINSTALLED_APPSに追加します

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git diff sample_application/settings.py
diff --git a/sample_application/settings.py b/sample_application/settings.py
index b2f36d7..22ccbe3 100644
--- a/sample_application/settings.py
+++ b/sample_application/settings.py
@@ -37,6 +37,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'sample_application'
]

MIDDLEWARE = [

では実行してみます

1
2
3
$ docker-compose run --rm web python manage.py dummy
Creating django_web_run ... done
execute Dummy command

無事実行できました!

まとめ

今回カスタムコマンドの追加方法を学びました。INSTALLED_APPSに追加していなかったところ以外はスムーズでした。通常はアプリケーションは追加されているはずなので、わざわざINSTALLED_APPSに追加するという説明はほとんど書かれていません。参考図書の実践Django Pythonによる本格Webアプリケーション開発にも、カスタムコマンドの追加に関しては3ページくらいさいてあるのですが(280ページ、管理コマンドの追加)、INSTALLED_APPSに追加しないと有効にならないとは記載されていません。わたしみたいな初心者しかここでは躓かないのかもしれませんね。

次回はこのコンテナを使ってカスタムコマンドをAWS Batchで実行しようと思います。

参考図書