django, python

djangoプロジェクトのdocker-compose化&DBを使う

前回、djangoでプロジェクト作成&hello worldでプロジェクトを作成してhelloworldページを表示するところまでやりました。
今回はモデルを定義してDBを使うところまでやります。

引き続き公式チュートリアルのほぼコピペです。

プロジェクトの設定ファイルであるmysite/settings.pyにDB設定を書いていきます。ここではpostgreSQLを使います。


と思ったのですが、実際のサービスデプロイをdockerでやろうと思っているのでdocker-compose&djangoで環境を作ることにします。

ちょうどいいドキュメントを見つけたのでこれに従ってやってみます。

djangoのプロジェクト直下(manage.pyがあるディレクトリ)にDockerfile, requirements.txt, docker-compose.ymlをそれぞれ作成します。

Dockerfile

FROM python:3.8

ENV PYTHONUNBUFFERED 1

RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

requirements.txt

Django>=3.0,<4.0
psycopg2-binary>=2.8

docker-compose.yml

version: '3'

services:
  db:
    image: postgres
    restart: always
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  web:
    build: .
    restart: always
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

DB設定

DB接続のための設定をします。PostgreSQLの場合です。
プロジェクト作成時に自動生成されたsettings.pyを編集します。DATABASESという箇所があるのでそこを書き換えます。デフォルトではsqlite3を使う設定になっています。

# postgresを使うための設定

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432,
    }
}

このDB名・ユーザー名・パスワードは、docker-compose内でdbイメージ作成時に環境変数で設定した値を書きます。
ホストのところが'db'となっていますがこれは、docker-composeのイメージ名を指定することでそのホストにアクセスできるようになっているためです(確かdocker-composeがイメージ名をホスト名として解釈してくれる)。
これでdocker-compose upすると、前回作ったhelloworldページへhttp://localhost:8000/polls/でアクセスできるようになります。とりあえずdocker-compose化ができました。
(DBは設定だけした状態なのでまだアプリ内では使っていませんが、DB名やユーザー名・パスワード等を正しく設定していないと起動時にエラーが出るはずです)

以降、manage.pyを使うコマンドなどターミナル上で実行するコマンドは基本的にdocker-compose経由で実行していきます。

DBを使う

setttings.pyのINSTALLED_APPSの値をみるとわかりますが、デフォルトでadmin, auth, contenttypesなどと言った「アプリ」が入っています。
これらの中にDBを必要とするものがあるので(adminやauthなど?)、マイグレーションをする必要があります。

$ docker-compose run web python manage.py migrate

このコマンドは、INSTALLED_APPに定義されているアプリに必要なDBテーブルを作成してくれます。その時にsettings.pyのDB設定を利用し、また各アプリで定義されているDBマイグレーションを利用するようです。

モデル定義

今度は自分でモデルを定義してみます。django.db.models.Modelのサブクラスとしてモデルを定義すると、そこからDBスキーマが自動で生成されます。
pollsアプリのモデルを定義するので、polls/models.pyを編集します。空のファイルがすでにあるはずです。

models.py

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

ここで各モデルに__str__()を定義していますが、これは対話環境で各レコードの中身をさらっと確認する時に便利ですし、自動生成されるadminでも利用されるため定義しておいた方が良いようです。

マイグレーション

このモデルに対応するDBテーブルを自動生成するためには、INSTALLED_APPSにpollsアプリを追加する必要があります。ここに追加するパスはpollsアプリのコンフィグクラスへのパスなので、今回の場合はpolls/apps.py内のPollsConfigというクラスを以下のように追記します。

settings.py

INSTALLED_APPS = [
    'polls.apps.PollsConfig', # この一行追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

で、以下のコマンドでdjangoにモデルの変更を知らせるとマイグレーションファイルが生成されます。

$ docker-compose run web python manage.py makemigrations polls

マイグレーションの内容と生成ファイルパスが以下のように標準出力されます。

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice

このマイグレーションファイルから生成されるSQLが気になる場合は以下のコマンドで確認することができます。これは指定されたマイグレーションファイルからSQLを生成するコマンドです。
(確認する必要がなければ実行する必要はありません)

$ docker-compose run web python manage.py sqlmigrate polls 0001

以下のコマンドでプロジェクトの構成チェックができますが、これはDBに関する不具合も検証してくれるようです(どんな不具合が起き得るのか、どんな不具合を検出できるのか不明)。

$ docker-compose run web python manage.py check

マイグレーションをするには以下のコマンドを実行します。

$ docker-compose run web python manage.py migrate

対話環境でモデルを使って遊ぶ

以下のコマンドでモデルを使って遊ぶことができます。DBの読み書きもちゃんとできます。

$ docker-compose run web python manage.py shell

以下のような感じです。

>>> from polls.models import Choice, Question

>>> Question.objects.all()
<QuerySet []>

>>> from django.utils import timezone
>>> q = Question(question_text="What's up?", pub_date=timezone.now())
>>> q.save()

>>> q.id
1
>>> q.question_text
"What's up?"

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です