TL;DR
素人基盤エンジニアがDockerでDjangoを触るシリーズ②:モデルの作成の続き。
1から読みたい場合は↓こちら。
素人基盤エンジニアがDockerでDjangoを触るシリーズ①:DockerでDjangoを作る
今回もDjango Girlsのサンプルを作りながらdjangoと戯れる。
前回はモデルを作成したので今回はViewとTemplateと行きたいところだが、先にDjangoモデルを管理するための管理サイト(admin)を学ぶ。
docker-composeで管理サイトのユーザ作成までを実行するには、作成コマンドであるcreatesuperuserをワンライナーで実行できるように、拡張したコマンドを作る必要があるので、それについても記載している。
Django admin
作成したモデルをGUIで管理するために、Djangoはデフォルトでadminというページを持っている。
今回はその有効化と使い方を見ていく。
①admin.pyの編集
admin.py
下記の通り編集する。
from django.contrib import admin
from .models import Post
admin.site.register(Post)
一行目は最初から入っているので、それ以外を追記する形。
よくわかる解説
from django.contrib import admin
adminサイトのアプリケーションモジュール。前回は特に触れなかったが、django.contrib.admin
は自分で作成したアプリケーションを追記したsettings.py
内のINSTALLED_APPS
にも、デフォルトで記載されており、最初から利用できるようになっている。
from .models import Post
同じディレクトリに格納されているmodels.pyから、Postモデルを呼び出している。
admin.site.register(Post)
admin.site.register(Model)
で、Modelをadminサイトの管理下に加えることができる。
ではいざ、起動しているコンテナでadminサイトをのぞいてみる。
(docker-compose up
は前回から起動しっぱなしの人は不要。)
docker-compose up
下記は別ターミナルから実行。前回は、python manage.py migrate blog
を実行してblogディレクトリ下のmigrationsのみマイグレーションしたが、今回は引数を与えずに実行することでadminのモデルもマイグレーションする。
docker-compose exec web bash
python manage.py migrate
exit
http://IPADDRESS:8000/admin
にアクセス
ログイン画面が開いた。ここに入るためのログインユーザは、DBのマイグレーションと同じようにmigrate.py
でコマンドを実行して作る必要がある。
②adminサイトのスーパーユーザの作成
docker-compose exec web bash
python manage.py createsuperuser
exit
createsuperuser
を実行すると、プロンプトが返ってくる。ユーザ名とメールアドレス、パスワードを入力すると、Superuser created successfully.
という出力があるので、ここで入力した情報を先ほどのログイン画面で入力する。
③レコードの操作
Postsというところをクリックしてみる。
POSTモデルは前回定義してテーブルを作成しただけなので、当然 0 postsと表示されている。ADD POSTというボタンでデータの挿入ができそうなので、押してみる。
前回models.pyで定義した通りに、入力用のテキストボックスやプルダウンリストが並んでいる。ためしに一つ投稿してみる。
無事データを追加できた。dbのコンテナに入って実際にレコードが入っているか見てみる。
docker-compose exec db bash
psql -U postgres
SELECT * FROM blog_post;
id | title | text | created_date | published_date | author_id
----+-------+--------------------+------------------------+------------------------+-----------
1 | TEST | This is test post. | 2020-05-02 07:47:14+00 | 2020-05-02 07:47:26+00 | 2
(1 row)
ちゃんとレコードが格納されていることを確認できた。レコードの作成、更新、削除も同じ画面で可能。
DB migrateやcreatesuperuser処理を含んだdocker-composeを作成する
これまで、あくまで検証のためということでdocker-compose exec
を使ってコンテナにログインして処理を行ってきたが、できればここまでをdocker-compose upで一気に構築できるほうがスマートだろう。
①DB migrate
migrateに関してはコマンドを打つのみなので、下記のようにdocker-compose.yamlのcommand:
を書き換えることで処理が可能である。(makemigrationはmigrationファイルを作成するだけなので、すでに作成済みのファイルがあれば必要ない。)
command: sh -c "sleep 5; python manage.py migrate; python manage.py runserver 0.0.0.0:8000"
migrateを実行する前に5秒sleepしているが、たまにPostgresの起動タイミングの問題でエラーが出るため追記している。
②createsuperuser
createsuperuserは実行時に対話的に処理が走るため、これをワンライナーで実行できるようにしないとdocker-composeでは扱えない。
ググると、manage.pyはmanagement/commands
というフォルダを作成してpythonファイルを追加してやれば、コマンドが拡張できるようだ。
https://stackoverflow.com/questions/6244382/how-to-automate-createsuperuser-on-django
https://docs.djangoproject.com/en/1.8/howto/custom-management-commands/
これを使ってユーザ名やパスワードをオプションで受け取ってワンライナーで実行可能なカスタムコマンドを作成する。
cd blog
mkdir -p management/commands
touch management/__init__.py
touch management/commands/__init__.py
createcustomsuperuser.py
from django.contrib.auth.management.commands import createsuperuser
from django.core.management import CommandError
class Command(createsuperuser.Command):
help = 'Crate a superuser, and allow password to be provided'
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--password', dest='password', default=None,
help='Specifies the password for the superuser.',
)
def handle(self, *args, **options):
password = options.get('password')
username = options.get('username')
database = options.get('database')
if password and not username:
raise CommandError("--username is required if specifying --password")
super().handle(*args, **options)
if password:
user = self.UserModel._default_manager.db_manager(database).get(username=username)
user.set_password(password)
user.save()
よくわかる解説
from django.contrib.auth.management.commands import createsuperuser
今回は、createsuperuserのコマンドを拡張するため、importする。
from django.core.management import CommandError
djangoが持っているコマンドエラー。今回は引数が足りないときにエラーを返すために利用。
class Command(createsuperuser.Command):
help = 'Crate a superuser, and allow password to be provided'
--help
もしくは-h
でヘルプを呼び出したときに表示される文言を追加。
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--password', dest='password', default=None,
help='Specifies the password for the superuser.',
)
コマンドの引数を追加する関数。super().add_arguments(parser)
は、元のcreatesuperuser
の引数も追加するために実行している。元のcreatesuperuserでは受け付けなかった、passwordという引数を追加。
def handle(self, *args, **options):
password = options.get('password')
username = options.get('username')
database = options.get('database')
if password and not username:
raise CommandError("--username is required if specifying --password")
super().handle(*args, **options)
if password:
user = self.UserModel._default_manager.db_manager(database).get(username=username)
user.set_password(password)
user.save()
実際の処理部分。従来のcreatesuperuserの処理により作成されたuserをdbから探してきて、passwordをセットして保存している。
このファイルを作成した上で、docker-compose.yamlを更に下記のように書き換える。
command: sh -c "sleep 5; python manage.py migrate; python manage.py createcustomsuperuser --username root --password 123456 --noinput --email 'blank@email.com'; python manage.py runserver 0.0.0.0:8000"
(パスワードは例)
このように、docker-compose.yamlに書けるということは、Kubernetesに移行するときもマニフェスト内でSecretで指定すればよさそうだ。
ここまでの処理が、docker-compose up
一行で完了することをぜひ各自確かめてほしい。
docker-compose up
次回は、urls.pyの書き方を学ぶ。(いつになったらViewを書くのか。。)