Djangoでカスタムコマンドを作る【Python】
- 作成日: 2021-01-08
- 更新日: 2023-12-24
- カテゴリ: Django
Djangoでカスタムコマンドを作る
Djangoのmanage.py
にコマンドを追加したい場合は、Djangoのカスタムコマンドを作成します。
カスタムコマンドを作成することでmanage.py
から使えるコマンドを増やすことが出来ます。
この記事ではこのカスタムコマンドの作り方を解説します。
具体的には↓を見ていきます。
- カスタムコマンドの概要
- プロジェクトを作る
- アプリを作る
- コマンドを作る
- コマンドを実行する
- コマンドの詳細について
カスタムコマンドの概要
Djangoのカスタムコマンドとは正確には「custom django-admin commands」のことを指します。
Djangoではアプリごとにコマンドを作ることが出来ます。
このコマンドはmanage.py
から実行することが出来ます。
たとえばshowposts
というコマンドを作った場合、↓のようにmanage.py
で実行することが可能です。
python manage.py showposts
Djangoで管理用にモデルを操作したり参照したりしたい場合に、ビューなどをわざわざ定義してブラウザから実行するのは非常に手間がかかり、めんどくさいことです。
しかし、カスタムコマンドを作ることでコマンドラインからモデル、ひいてはプロジェクト全体を参照することが可能になり、非常に便利になります。
カスタムコマンドを作りcron
などのスケジューラ―と組み合わせれば、定期的にプロジェクトに変更を加えるシステムも構築することが出来ます。
Djangoのカスタムコマンドはインストールしたアプリ以下にmanagement
というディレクトリを作り、その下にcommands
というディレクトリを作ります。そしてコマンド名に相当するモジュールを配置し、モジュールの中でコマンドのクラスを作ることでDjangoがそのコマンドを認識します。
たとえばbbs
というアプリを作り、その下にコマンドを配置する場合は↓のようなディレクトリ構造になります。
./bbs
├── admin.py
├── apps.py
├── __init__.py
├── management # <-- これがコマンドを管理するディレクトリ
│ └── commands # <-- これがコマンドを配置するディレクトリ
│ ├── __init__.py
│ └── showposts.py # <-- これがコマンド本体。ファイル名がコマンド名になる
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
↑のようにshowposts
というコマンドを作った場合、manage.py
を実行すると↓のようにコマンドが表示されます。
$ python manage.py
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
...
[bbs]
showposts
...
プロジェクトを作る
今回の解説のためにプロジェクトを作ります。
掲示板を作るという想定で、プロジェクト名は「mybbs」とします。
$ django-admin startproject mybbs
アプリを作る
続いてアプリを作成します。
これも掲示板アプリという想定でアプリ名は「bbs」とします。
$ python manage.py startapp bbs
アプリのカスタムコマンドをDjangoに認識させるには、アプリをプロジェクトにインストールしておく必要があります。
プロジェクトのsettings.py
のINSTALLED_APPS
を編集して忘れずにアプリをインストールしておくようにします。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bbs',
]
モデルを作る
今回はテスト用にPost
というモデルを作ります。
これはbbs
アプリの掲示板の投稿内容を表すモデルです。
from django.db import models
class Post(models.Model):
name = models.CharField(max_length=128, help_text='投稿者名')
content = models.TextField(max_length=1024, help_text='投稿内容')
モデルを定義したら忘れずにマイグレーションを済ませておきます。
$ python manage.py makemigrations
$ python manage.py migrate
コマンドを作る
アプリのコマンドを実際に作っていきます。
bbs
アプリ以下にmanagement
ディレクトリを作り、その下にcommands
ディレクトリを作ります。
$ cd bbs
$ mkdir management
$ mkdir management/commands
commands
ディレクトリ以下にshowposts.py
というファイルを作ります。
このshowposts
というファイル名がそのままコマンド名になります。
今回は掲示板の投稿(Post)を一覧表示するコマンドという想定です。
showposts.py
は↓のように書いておきます。
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
help = 'Show post list'
def handle(self, *args, **options):
self.stdout.write('show posts')
↑のようにモジュール内にCommand
というクラスを作ります。
このクラスはBaseCommand
を継承するようにします。
そしてhelp
属性にコマンドの説明を書いておきます。
handle()
メソッドをオーバーライドして、コマンドが実行されたときの処理を書きます。
↑の場合は標準出力に「show posts」と出力しています。
コマンドを実行する
コマンドを作成したので↓のようにコマンドを実行します。
$ python manage.py showposts
show posts
すると↑のように「show posts」と出力されます。
-h
オプションを指定して実行するとコマンドの使い方が表示されます。
$ python manage.py showposts -h
usage: manage.py showposts [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color] [--force-color] [--skip-checks]
Show post list
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.
--force-color Force colorization of the command output.
--skip-checks Skip system checks.
コマンドの詳細について
ここからコマンドの詳細について見ていきます。
標準出力と標準エラーについて
コマンドで標準出力と標準エラーを使うにはそれぞれself.stdout
とself.stderr
を使うのが推奨されています。
これらのファイルオブジェクトを使うことでコマンドのテストやデバッグがしやすくなります。
def handle(self, *args, **options):
self.stdout.write('success')
self.stderr.write('error')
また、これらのオブジェクトのwrite()
メソッドは改行を自動で付加します。そのため開発者が行末に改行を付加する必要はありません。
改行を取り除きたい場合はending
引数に空文字列を指定します。
def handle(self, *args, **options):
self.stdout.write('success', ending='')
self.stderr.write('error', ending='')
引数の追加
コマンドはデフォルトでは引数を取りません。
しかしコマンドが引数を取るようにしたい場合があります。
たとえばcreatepost
というコマンドからPost
を作成する場合、コマンドラインからその属性値を指定できるようにした方が便利です。
↓のようにです。
$ python manage.py createpost postname postcontent
そういう場合は↓のようにします。
from django.core.management.base import BaseCommand, CommandError
from bbs.models import Post
class Command(BaseCommand):
help = 'Create post'
def add_arguments(self, parser):
parser.add_argument('attrs', nargs='+', type=str)
def handle(self, *args, **options):
attrs = options['attrs']
print(attrs)
post = Post.objects.create(name=attrs[0], content=attrs[1])
print(post.name, post.content)
↑のようにadd_arguments()
というメソッドをオーバーライドして、parser
に引数の定義を追加します。
parser.add_argument('attrs', nargs='+', type=str)
は可変長の文字列の引数attrs
を定義しています。
このcreatepost
コマンドを実行すると↓のように出力されます。
['postname', 'postcontent']
postname postcontent
↑の出力を見るとoptions
に格納されているattrs
は文字列の入ったリストであることがわかります。
また、そのリストの第1引数をname
, 第2引数をcontent
に設定してPost
オブジェクトを作成し、結果が成功していることもわかります。
オプションの追加
コマンドにオプションを追加するには↓のようにadd_arguments()
を編集します。
from django.core.management.base import BaseCommand, CommandError
from bbs.models import Post
class Command(BaseCommand):
help = 'Create post'
def add_arguments(self, parser):
parser.add_argument('-n', '--name', required=True, type=str)
parser.add_argument('-c', '--content', required=True, type=str)
def handle(self, *args, **options):
name = options['name']
content = options['content']
post = Post.objects.create(name=name, content=content)
print(post.name, post.content)
↑の場合、コマンドにオプション-n
と--name
, -c
と--content
を追加しています。
これらのオプションは必須(required=True
)で、タイプは文字列(type=str
)です。
-n
と--name
はPost
のname
の指定で、-c
と--content
はPost
のcontent
の指定です。
↑のコマンド(createpost
)を実行すると↓のように出力されます。
$ python manage.py createpost --name postname --content postcontent
postname postcontent
これらの引数の設定はparser
に対して行いますが、その他のオプションの設定方法についてはargparse
モジュールを参照してください。
おわりに
今回はDjangoのカスタムコマンドの作り方を紹介しました。
カスタムコマンドを作れるようになるとDjangoを自動化することが出来るようになります。
押さえておきたいところですね。
🦝 < 困ったらカスタムコマンド