ご質問・お見積り等お気軽にご相談ください
お問い合わせ

pythonのWebフレームワーク、Djangoにチャレンジ!–その2:dockerを用いた環境構築やDBのマイグレーション–

pythonのWebフレームワーク、Djangoにチャレンジ!–その2:dockerを用いた環境構築やDBのマイグレーション–

2023年12月23日追記:ディレクトリの表示方法を修正しました。

この度は、株式会社ウェブネーションをご訪問頂き、誠にありがとうございます。

今回は、巷で人気のプログラミング言語python、その中のWebフレームワーク、djangoを使ってWeb開発にチャレンジしてみましたので、その手順の一部を紹介いたします。

しかしながら、内容の規模が少々大きく見込まれるため、いくつかパートに分けて紹介いたします。今回はdockerを用いた環境構築やDB(データベース)のマイグレーションです。

最後までお読みいただけますと幸いです。

なお、DBはPostgreSQL、Dockerコンテナはboards-app(Appサーバ用コンテナ)とboards-db(DBサーバ用コンテナ)の二つを、それぞれ使います。

※Dockerコンテナの名称につきまして、こちらは基本的に自由ですが、今回は各コンテナの役割を明確にすべく、上記のように掲載いたしました。

前提条件

  1. Windowsではコマンドプロンプトが、Macではターミナルが起動できていること
  2. 下記2点の言語/ツールがインストールされていること
    • python
    • pip ← pythonのパッケージ管理ツール
  3. Djangoの仮想環境構築やパッケージ管理ができる環境になっていること
  4. Docker Desktopがインストールされていること
  5. 下記のディレクトリ構成になっていること
boards
├── Pipfile
├── Pipfile.lock
├── boards
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

環境変数の設定

まずは環境変数を設定します。なお、下記の記事を参考にしました(2023年11月26日閲覧)。

コマンドプロンプト/ターミナル(環境変数設定)

# Pipfileが含まれる方のboardsディレクトリまで移動
cd [Pipfileが含まれる方のboardsディレクトリ]
# lsコマンドを入力してファイルリストが下記5つの通りであれば次に進みます。
ls
Pipfile		Pipfile.lock	boards		config		manage.py
# djangoの環境変数管理モジュールdjango-environをインストール(2023年11月26日時点で最新バージョンは0.11.2です)[1]
pipenv install django-environ~=0.11.2
# 環境変数管理ファイルを新規追加
touch .env

.env

# ※1:この印が加えられた行につきまして、開発環境は適当な文字列で差し支えありませんが、仮に本番環境で使用する場合、セキュリティ対策の観点から、秘密鍵用の文字列とパスワードはいずれも、ランダムかつ長い文字列を必ずお使いください。
# ※2:Dockerのコンテナboards-dbとコンテナ名が同一でなければ、サーバが正常に稼働できなくなります。

# djangoのコードで使用する環境変数
DEBUG=True
SECRET_KEY=[秘密鍵用の文字列] ※1
ALLOWED_HOSTS=*
DATABASE_ENGINE=django.db.backends.postgresql [<-DjangoでのPostgreSQLのDBエンジン]
DATABASE_DB=boards-db [<-データベース名] ※2
DATABASE_USER=[データベースのユーザー名]
DATABASE_PASSWORD=[データベースのパスワード] ※1
DATABASE_HOST=[データベースのホスト名]
DATABASE_PORT=5432 [<-PostgreSQLのポート番号]

# docker-compose.ymlで使うコンテナboards-dbの環境変数
POSTGRES_DB=boards-db [<-データベース名] ※2
POSTGRES_USER=[データベースのユーザー名]
POSTGRES_PASSWORD=[データベースのパスワード] ※1

続いて、Djangoの環境設定を行うため、既に生成されたsettings.pyを、コード内の「変更箇所」の通りに変更します。

config/settings.py

...

# ----------- 変更箇所(始) ------------
import environ
# ----------- 変更箇所(終) ------------
from pathlib import Path

# ----------- 変更箇所(始) ------------
env = environ.Env(
    # 万が一環境変数が読み込めなかった時に備え、デフォルト値をあらかじめ確保(今回はDEBUGのみ)
    DEBUG=(bool, False)
)

# 環境変数を読み込む
environ.Env.read_env()
# ----------- 変更箇所(終) ------------

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

...

# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/]

# ----------- 変更箇所(始) ------------
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG')

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
# ----------- 変更箇所(終) ------------

...

INSTALLED_APPS = [
    ...
    'django.contrib.staticfiles',
    # ----------- 変更箇所(始) ------------
    'boards', # <- この箇所はconfig/settings.pyの上位ディレクトリboardsと、ディレクトリ名が同一でないと、コンテナboards-appのサーバが稼働しない。
    # ----------- 変更箇所(終) ------------
]

...

# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        # ----------- 変更箇所(始) ------------
        'ENGINE': env('DATABASE_ENGINE'),
        'NAME': env('DATABASE_DB'), # <- この箇所はDockerのコンテナboards-dbとコンテナ名が同一でなければサーバが正常に稼働できなくなる。
        'USER': env('DATABASE_USER'),
        'PASSWORD': env('DATABASE_PASSWORD'),
        'HOST': env('DATABASE_HOST'),
        'PORT': env('DATABASE_PORT'),
        # ----------- 変更箇所(終) ------------
    }
}

...

# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
# ----------- 変更箇所(始) ------------
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
# ----------- 変更箇所(終) ------------

USE_I18N = True

...

dockerを用いた環境構築

仮想環境にインストールしたいパッケージをまとめたテキストファイルを新しく用意し、そのファイルにそれらのパッケージを入力します。

コマンドプロンプト/ターミナル(requirements.txt追加)

touch requirements.txt

requirements.txt

django
django-environ

続いて、Dockerでの環境構築に必要なファイルを新しく追加し、DockerイメージとDockerコンテナの設定を加えていきます。

コマンドプロンプト/ターミナル(DockerイメージとDockerコンテナの設定追加)

touch Dockerfile
touch docker-compose.yml

Dockerfile

FROM python:3.11

# Dockerコンテナ上の作業用ディレクトリ設定
WORKDIR /usr/src/app

# __pychache__/pycの生成を無効にする
ENV PYTHONDONTWRITEBYTECODE 1
# 標準入出力におけるpythonのバッファリングを無効にする
ENV PYTHONUNBUFFERED 1

# 仮想環境にインストールしたいパッケージをまとめたテキストファイルを、Dockerにコピー
COPY ./requirements.txt /usr/src/app/requirements.txt

# pip(パッケージ管理), pipenv(仮想環境構築/パッケージ管理)で必要なモジュールを、コンテナboards-appへインストール
RUN pip install --upgrade pip \
&& pip install pipenv \
&& pip install psycopg2 \
&& pipenv install \
&& pipenv install -r requirements.txt
# psycopg2:pythonでpostgreSQLを使えるようにするためのライブラリ

# Dockerコンテナ上のpythonパッケージ管理用ファイルを、Dockerにコピー
COPY ./Pipfile /usr/src/app/Pipfile

# --system:システムのpipコマンドを使用[3]
RUN pipenv install --system

# Dockerコンテナ上のカレントディレクトリ(現在のディレクトリ)をDockerにコピー
COPY . /usr/src/app/

docker-compose.yml

version: '3.11'

services:
  boards-app:
    build: ./
    # 5秒待機後、コンテナboards-appのサーバを起動
    command: > 
       sh -c "sleep 5 &&
              python manage.py runserver 0.0.0.0:8000"
    volumes: 
      - ./:/usr/src/app
    ports: 
      - "8000:8000"
    env_file: .env
    # コンテナboards-dbを依存コンテナにする
    depends_on:
      - boards-db

  boards-db:
    image: postgres:16
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports: 
      - "5432:5432"
    env_file: .env

volumes:
  postgres_data:

上記の通りに入力できたら、下記のコマンドを実行します。

コマンドプロンプト/ターミナル(dockerビルド&起動)

# -dオプションを適用しない場合、コマンドプロンプト/ターミナルにDockerのログが出力される。
docker-compose up -d --build

端末によっては時間がかかりますが、下記のメッセージがコマンドプロンプト/ターミナルに出力できたら、Dockerのビルドと起動が完了となります。

[+] Running 4/4                                                                                                        
 ✔ Network [ネットワーク名]         Created                                       
 ✔ Volume "[DockerVolume]"     Created
 ✔ Container [コンテナboards-dbのサーバ]   Started
 ✔ Container [コンテナboards-appのサーバ]  Started    

この時点でDocker Desktopを起動すると、二つのコンテナが、下の画像のように、いずれもエメラルド色で表示されていることが確認できると思います。

その後ブラウザを起動して、URLに「localhost:8000」と入力し、読込後下の画像が画面に表示できたら、Dockerでの環境構築は成功です。

dockerを用いたDBのマイグレーション

DBのマイグレーションを行うため、既に生成されたmodels.pyとadmin.py、docker-compose.ymlを、コード内の「変更箇所」の通りに変更します。

なお、DBのマイグレーションとは、既に生成されたファイルmodels.pyに、新しいモデルを作成することで、新しいDB構造が自動生成される機能のことです。[5]

今回はmessageというDBテーブルを使って、DBのマイグレーションを行います。

boards/models.py

from django.db import models

# Create your models here.
# ----------- 変更箇所(始) ------------
class message(models.Model):
    user_name = models.CharField(max_length=50)
    title = models.CharField(max_length=50)
    body = models.CharField(max_length=200)
    post_at = models.DateTimeField(auto_now_add=True)
# ----------- 変更箇所(終) ------------

boards/admin.py

from django.contrib import admin
# ----------- 変更箇所(始) ------------
from .models import message
# ----------- 変更箇所(終) ------------

# Register your models here.
# ----------- 変更箇所(始) ------------
admin.site.register(message)
# ----------- 変更箇所(終) ------------

docker-compose.yml

...
services:
  boards-app:
    ...
    command: > 
       sh -c "sleep 5 &&
              # ----------- 変更箇所(始) ------------
              python manage.py makemigrations &&
              python manage.py migrate &&
              # ----------- 変更箇所(終) ------------
              python manage.py runserver 0.0.0.0:8000"
    ...

上記の通りに入力できたら、一度生成したDockerコンテナを下記コマンドで削除し、再生成します。

※Dockerイメージも必要があれば削除して構いませんが、ビルドで長い時間を要することになります。

コマンドプロンプト/ターミナル(dockerコンテナ削除&ビルド&起動)

# -vオプションを適用すれば、現在確保されているコンテナboards-db内のDockerVolumeである、DBのデータも削除してくれる。
docker-compose down -v
# -dオプションを適用しない場合、コマンドプロンプト/ターミナルにDockerのログが出力される。
docker-compose up -d --build

Docker Desktopにて、コンテナboards-appとboards-dbのサーバの起動がいずれも確認できたら、コンテナboards-dbをクリックします。

下の画像が確認できたら、続いて「Exec」と書かれたタブをクリックします。

「#」が出力されたら、下記のコマンドを実行します。

コードで掲載されている表のうち、下から5行目の行の出力が確認できたら、DockerでのDBのマイグレーションはひとまず完了です。

Dockerコンテナ上のターミナル

# Postgresへ接続
psql -d [データベース名]
# 「\dt」を入力してEnterキーを押下
[データベース名]=# \dt
# 下記の表のうち、下から5行目の行の出力が確認できたら、DockerでのDBのマイグレーションはひとまず完了
                  List of relations
 Schema |            Name            | Type  |        Owner 
--------+----------------------------+-------+-----------------------
 public | auth_group                 | table | [データベースのユーザー名]
 public | auth_group_permissions     | table | [データベースのユーザー名]
 public | auth_permission            | table | [データベースのユーザー名]
 public | auth_user                  | table | [データベースのユーザー名]
 public | auth_user_groups           | table | [データベースのユーザー名]
 public | auth_user_user_permissions | table | [データベースのユーザー名]
 public | boards_message             | table | [データベースのユーザー名] <- コレ
 public | django_admin_log           | table | [データベースのユーザー名]
 public | django_content_type        | table | [データベースのユーザー名]
 public | django_migrations          | table | [データベースのユーザー名]
 public | django_session             | table | [データベースのユーザー名]
(11 rows)

なお、この時点でのディレクトリは下記の状態になると思います。

boards
├── .env
├── Dockerfile
├── Pipfile
├── Pipfile.lock
├── boards
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── docker-compose.yml
├── manage.py
└── requirements.txt

最後に

いかがでしたでしょうか?

Dockerでの環境構築は、ご覧のように最初こそ確かに面倒ですが、上の操作を行えば毎回runserverコマンドを打たずに済みますので、特にチームでの開発効率の向上には貢献できる技術だと思います。

次回は、Djangoにおける、管理者権限の作成とその自動化の方法について紹介いたします。

今回はここまでとさせていただきます。

最後までお読みいただき、誠にありがとうございます。

参考リンク

  1. django-environ 0.11.2(2023年11月26日閲覧)
  2. Django & Postgres with Docker Best Practices(2023年11月26日閲覧)
  3. Pipenvの基本的な使い方(2023年11月26日閲覧)
  4. DockerでDjangoの開発環境を構築!(Docker-compose/Django/postgreSQL/nginx)(2023年11月27日閲覧)
  5. Migrations | Django documentation | Django(2023年11月27日閲覧)

過去の記事

この記事を書いた人
通りすがりのエンジニアB
通りすがりのエンジニアB(匿名)です。