読者です 読者をやめる 読者になる 読者になる

Djangoの管理コマンドを作る際にdjango-extensionsのcreate_commandコマンドを使う

Python Django

Djangoのmanage.pyスクリプトのサブコマンド(管理コマンド、management command)を追加するには、Djangoアプリケーション内に「management/commands/コマンド名.py」のようにモジュールを作成しますが、頻繁に使うわけでもないので作法をよく忘れてしまってます。
django-extensionsにはcreate_commandという便利なコマンドがあり、ディレクトリの作成とスケルトンの作成をしてくれます。
Current Command Extensions — django-extensions 1.6.7 documentation
django-extensions/create_command.py at master · django-extensions/django-extensions · GitHub
Python 3.4、Django 1.8.4、django-extensions 1.5.5の環境で試しました。

django-extensinosを有効にする

django-extensionsはpipでインストールできます。

$ pip install django-extensions

settings.pyのINSTALLED_APPSに「django_extensions」を追加します。

# settings.py抜粋
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_extensions',  # この行を追加
    'myapp',
)

これでdjango-extensionsが有効になります。

create_commandを使う

create_commandコマンドでディレクトリとスケルトンを作成します。
引数にはコマンドを追加したいアプリケーション名を指定します。--nameオプションで作成するコマンド名を指定することもできます(省略するとsample)

$ python manage.py create_command myapp --name=hello

myappというアプリケーションにhelloコマンドを作成しました。
ディレクトリとファイルのレイアウトは次のようになります。

$ tree myapp/
myapp/
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-34.pyc
│   ├── admin.cpython-34.pyc
│   └── models.cpython-34.pyc
├── admin.py
├── management
│   ├── __init__.py
│   └── commands
│       ├── __init__.py
│       └── hello.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

作成したコマンドを見てみる

作成したコマンドは、すぐに実行出来る状態です。
実行するとNotImplementedError(未実装の意味の例外)が発生して終了します。

$ python manage.py hello
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/tokibito/tmp/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/tokibito/tmp/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/tokibito/tmp/venv/lib/python3.4/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/tokibito/tmp/venv/lib/python3.4/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/home/tokibito/tmp/mysite/myapp/management/commands/hello.py", line 7, in handle
    raise NotImplementedError()
NotImplementedError

コードを見てみます。
myapp/management/commands/hello.py

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "My shiny new management command."

    def handle(self, *args, **options):
        raise NotImplementedError()

handleメソッドにコマンドで実行したい内容を記述できます。
例えば、「Hello, world!」とprintするコマンドであれば、次のようになります。

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "My shiny new management command."

    def handle(self, *args, **options):
        print("Hello, world!")
実行結果
$ python manage.py hello
Hello, world!

このように管理コマンドを追加したいときにちょっとだけ楽をできます。使うと良いかもしれません。