Python
Django
DjangoDay 20

Djangoのカスタムコマンドを作成してコマンドラインから実行する

More than 1 year has passed since last update.


Djangoのカスタムコマンドを作成してコマンドラインから処理を実行する


はじめに

Webアプリケーションの開発を行っていると、コマンドラインから特定の処理(集計処理、API呼び出し、メール配信など)を実行したい場合があります。この記事ではDjangoアプリケーションをコマンドラインから実行する処理の書き方を紹介します。


Djangoのコマンドラインツール

Djangoにはデフォルトでコマンドラインツールが付属しており、例えば次のような処理をコマンドラインから実行することができます。

python manage.py startapp sample => アプリケーションの作成

python manage.py migrate => DBマイグレーションの実行
python manage.py shell => インタラクティブShellの起動
python manage.py runserver => 開発サーバーの起動

この他にも様々なコマンドが用意されておりpython manage.pyとタイプすると、使用できるコマンドの一覧を表示できます。

% python manage.py      

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

Available subcommands:

[auth]
changepassword
createsuperuser

[debug_toolbar]
debugsqlshell

[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

より詳細に特定のコマンドのヘルプを参照するにはpython manage.py help runserverのようにhelpに続けて参照したいコマンドの名称を入力します。

% python manage.py help runserver     

usage: manage.py runserver [-h] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color] [--ipv6] [--nothreading]
[--noreload] [--nostatic] [--insecure]
[addrport]

Starts a lightweight Web server for development and also serves static files.

positional arguments:
addrport Optional port number, or ipaddr:port

optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn'
t provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--ipv6, -6 Tells Django to use an IPv6 address.
--nothreading Tells Django to NOT use threading.
--noreload Tells Django to NOT use the auto-reloader.
--nostatic Tells Django to NOT automatically serve static files
at STATIC_URL.
--insecure Allows serving static files even if DEBUG is False.


Djangoのカスタムコマンドの作成

Djangoのコマンドラインツールには、コマンドを追加するための仕組みが用意されています。カスタムコマンドを追加すると、次のようにコマンドラインツールから実行することができます。

python manage.py <カスタムコマンド名>


サンプル

今回はこちらのブログ管理アプリケーションにカスタムコマンドを追加し、実行してみましょう。最終的なソースコードはリンク先のGithubの内容を確認してください。

ブログ管理アプリケーションのblogディレクトリの構成は以下の通りです。

├── blog

│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations/
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── django_sample/
├── manage.py
└── requirements.txt


ディレクトリの作成

まずはblogアプリケーション配下に、コマンドを格納するためのディレクトリ(management/commands)を作成します。

mkdir -p blog/management/commands

touch blog/management/__init__.py
touch blog/management/commands/__init__.py


コマンドの作成

次に作成したディレクトリ(management/commands/)にコマンド本体となるcount_entry.pyを作成します。

vi blog/management/commands/count_entry.py

カスタムコマンドはBaseCommandクラスを継承してクラスを作成します。実際の処理本体はhandleメソッド内に記載します。今回は引数で渡されたブログの記事数を表示するプログラムを作成します。


count_entry.py

# -*- coding:utf-8 -*-

from django.core.management.base import BaseCommand

from ...models import Article

# BaseCommandを継承して作成
class Command(BaseCommand):
# python manage.py help count_entryで表示されるメッセージ
help = 'Display the number of blog articles'

# コマンドライン引数を指定します。(argparseモジュール https://docs.python.org/2.7/library/argparse.html)
# 今回はblog_idという名前で取得する。(引数は最低でも1個, int型)
def add_arguments(self, parser):
parser.add_argument('blog_id', nargs='+', type=int)

# コマンドが実行された際に呼ばれるメソッド
def handle(self, *args, **options):
for blog_id in options['blog_id']:
articles_count = Article.objects.filter(blog_id=blog_id).count()

self.stdout.write(self.style.SUCCESS('Article count = "%s"' % articles_count))


最終的なディレクトリ構成は次の通りです。

blog

├── __init__.py
├── admin.py
├── apps.py
├── forms.py
├── management => カスタムコマンドを格納するディレクトリ
│   ├── __init__.py
│   └── commands
│   ├── __init__.py
│   └── count_entry.py
├── migrations/
├── models.py
├── tests.py
├── urls.py
└── views.py


カスタムコマンドの実行

作成したカスタムコマンドを実行してみましょう。はじめにpython manage.pyを実行して、カスタムコマンドが追加されているか確認します。

% python manage.py 

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

Available subcommands:

[auth]
changepassword
createsuperuser

[blog]
count_entry => 追加されている

[debug_toolbar]
debugsqlshell

[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

count_entryコマンドが追加されています。次にpython manage.py count_entry 1と入力し、作成したカスタムコマンドを実行します。

% python manage.py count_entry 1

Article count = "2"

カスタムコマンドが実行され、ブログの記事数が表示されました。また通常のDjangoのコマンドと同様にhelpコマンドも使用することができます。作成されたコマンドは通常のスクリプトと同じように、cronなどを利用して定期的に実行することも可能です。


終わりに

今回はDjangoのコマンドラインツールから実行できるカスタムコマンドの作成方法をご紹介しました。cronなどで定期的に処理を実行したい場合など、独自のコマンドを作成するケースはたくさんあると思います。ぜひDjangoのカスタムコマンドを作成し、活用してみてはいかがでしょうか。それでは楽しいDjangoライフを!


参考サイト