銀月の符号

Python 使い見習いの日記・雑記

manage.py コマンドの追加

Python 札幌第3回開催直前、便乗 Django ネタ。第2回未参加なので既出かも。 manage.py にオリジナルのコマンドを追加する方法について。また、 manage.py shell インタラクティブシェルで実験したいけれど長くなりそう、というときの代わりにも使える。「アクションを追加する」も参照。

コマンド名.py というファイルを作る。雛形は以下。 BaseCommand を継承した Command という名のクラスを作る。そして handle というメソッドを作る。この中に動作を書く。

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, *args, **options):
        pass

たとえば、あるモデル spam.models.Spamインスタンス一覧表示をしたいならこんな感じで。

from django.core.management.base import BaseCommand
from spam.models import Spam

class Command(BaseCommand):
    def handle(self, *args, **options):
        for spam in Spam.objects.all():
            print spam

とはいえ、このような引数を必要としないシンプルなコマンドの場合は BaseCommand の代わりに NoArgsCommand を使用するのが正しい作法の模様。こちらの場合は handle_noargs メソッドを使う。

from django.core.management.base import NoArgsCommand

class Command(NoArgsCommand):
    def handle_noargs(self, **options):
        pass

オプションの設定は optparse モジュールの知識があればすごく楽。知らなければ少々面倒かもしれないけれど optparse モジュールのドキュメントを参照。 Option インスタンスのリストを option_list クラス変数につくってあげれば、パーサの設定、解析などは BaseCommand がやってくれる。以下の例は django/core/management/commands/shell.py より --plain オプションを追加するというもの。

from django.core.management.base import NoArgsCommand
from optparse import make_option

class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list + (
        make_option('--plain', action='store_true', dest='plain',
            help='Tells Django to use plain Python, not IPython.'),
    )

このファイルの置き場所は app_dir/management/commands の中。また、 management, commands は Python パッケージである必要がある。とりあえず空の __init__.py を置いておくとよい。 Django では設定ファイルすら Python モジュールなので、コマンドが Django アプリ(これも Python パッケージ)のサブパッケージでも違和感はない。むしろしっくりくる。