MENU

Django+docker+poetryで開発

Django+poetry+dockerで開発

今回は、タイトルのとおり、Django+Poetry+dockerで開発環境を作っていきます。

ボリュームはかなり多めですが、お付き合いください。

それでは早速始めていきましょう。

目次

プロジェクト用のディレクトリを作成

初めにプロジェクトのディレクトリを作成してしまいます。
以下のコマンドを実行し、ディレクトを作成していきます。

mkdir app
cd app
touch docker-compose.yml
mkdir backend
touch Dockerfile

docker-compose.ymlの作成

それでは、作成したdocker-compose.ymlを編集していきます。
以下のように記述します。

services:
  backend:
    container_name: backend
    build:
      context: ./backend
      dockerfile: Dockerfile
    volumes:
      - ./backend/.dockervenv/:/backend/.venv/
      - ./backend/:/backend/
      - static:/backend/static_root
      - media:/backend/media
    ports:
      - 8000:8000

volumes:
  static:
  media:
  pgdata:

今回のdocker-compose.ymlの設定は、

  • backendというコンテナを設定しています。
  • container_nameで任意のコンテナ名を設定しています。これは任意のフィールドなので、なければ先に設定したbackendがコンテナ名になります。
  • buildにはDockerfileの場所を記載しています。
  • volumesにはdockerにバインドするディレクトリを設定しています。
  • volumesの1行目は、poetry(後述)によるライブラリ等をインストールしたディレクトリをdockerへバインドするものです。
  • volumesの2行目は、プロジェクトのバインド設定になります。
  • volumesの3行目、4行目はDjangoのメディアファイルのバインドを設定しています。

参考にした記事を載せておきますので、こちらも確認してみてください。
(一部FastAPIに関する記事内のdockerの設定を転用しています)

Dockerfileの設定

次に先ほどdocker-compose.ymlで指定した「Dockerfile」の設定をしていきます。

以下のとおり記述してみてください。

FROM python:3.10

ENV PYTHONUNBUFFERED 1

WORKDIR /backend

RUN pip install poetry

COPY pyproject.toml* poetry.lock* ./

# poetryでライブラリをインストール (pyproject.tomlが既にある場合)
RUN poetry config virtualenvs.in-project false
RUN if [ -f pyproject.toml ]; then poetry install; fi

# poetryの実行用コマンド
ENTRYPOINT ["poetry", "run"]

COPY . /backend

今回の設定は以下のとおりです。

  • FROM python:3.10」:dockerの公式imageからpythonの3.10をインストールします。
  • ENV PYTHONUNBUFFERED 1」:「非空(空でない文字列がセットされたら)なら標準出力・標準エラーのストリームのバッファリングを行わない」設定となります。
  • WORKDIR /backend」:今回のワーキングディレクトリを示しています。
  • RUN pip install poetry」:dockerのbuild時にこのコマンドを実行して、poetryをインストールするように設定しています。
  • COPY pyproject.toml* poetry.lock* ./」:poetryにより生成されるpyproject.tomlをdockerにコピーします。
  • RUN poetry config virtualenvs.in-project false」:venv のファイルをプロジェクトディレクトリの下に置きたい場合に記載します。
  • RUN if [ -f pyproject.toml ]; then poetry install; fi」:pyproject.tomlの存在を確認し、poetryによるインストールコマンドを実行します。
  • ENTRYPOINT ["poetry", "run"]」:poetryを操作する場合のコマンドを設定しています。
  • COPY . /backend」:dockerに現在のディレクトリをコピーします。

正直、私も見よう見まねでやったところ、これでうまくいった感じがあります。
ひとまずこの設定でいきます。

docker環境の構築

それでは、ここまで記述したところで、以下のコマンドを順番に実行し、dockerの環境を構築していきます。

docker環境のビルド

まずは、以下のコマンドでbuildコマンドでdockerのコンテナを立ち上げます。

docker-compose build

次に、docker-composeのrunコマンドでentrypointに記載したpoetryのコマンドでpoetry initを実行します。
また、初めから必要なライブラリ等をインストールしておきます。

docker-compose run --entrypoint "poetry init --name backend --dependency django --dependency psycopg2 --dependency psycopg2-binary --dependency djoser --dependency pydantic --dependency django-cors-headers --dependency djangorestframework --dependency pillow --dependency django-ninja" backend

記述しているライブラリ等は以下のとおりです。

  • django
  • psycopg2:PostgreSQL アダプター
  • psycopg2-binary
  • djoser:DRFによる登録、ログイン、ログアウト、パスワードのリセット、アカウントの有効化などの基本的なアクションを処理するために使用します(DRFをインストールするので一緒にインストールしておく)
  • pydantic:Pythonの型ヒントを使用したデータ検証と設定管理を行います。
  • django-cors-headers:最終的にはReactを用いてフロントエンドを実装するため、事前にインストールをしていきます。
  • djangorestframework:DjangoにおけるRESTfulなWebAPIを作成するためのライブラリです。
  • pillow:画像の処理機能を提供するライブラリ
  • django-ninja:FastAPIに似た機能を持つ、OpenAPIの提供のためのライブラリ。今回はこれをメインに実装するかもしれません。

さらに、poetry initで生成したpyproject.tomlをベースに、下記のコマンドでライブラリ等のインストールを実行します。

docker-compose run --entrypoint "poetry install" backend

そして、インストールを実行後、以下のコマンドで再度dockerのコンテナをビルドします。
これによりコンテナ内でインストールしたライブラリ等が使えるようになります。
※何か設定が変わったり、ライブラリ等を追加でインストールしたときは、下記のコマンドを実行してください。

docker-compose build --no-cache

最後に、buildしたコンテナを下記のコマンドで実行し、立ち上げます。

docker-compose up

以上がdockerのコンテナを立ち上げる作業となります。
これでバックエンド用のdockerのコンテナが起動しますし、仮想環境の構築もされます。

手順としてdocker-compose upを実行するよう示していますが、実際には以下のdjangoプロジェクトの作成を先に実行する必要があります。

djangoのプロジェクトを作成

プロジェクトの立ち上げ

それでは、Djangoのプロジェクトを立ち上げていきます。
今回は、ローカル環境でDjangoを直接立ち上げるわけではなく、dockerを使用しているため、少し実行用のコマンドが異なります。

まずは、下記のコマンドでdocker経由でdjangoのプロジェクトを立ち上げます。

docker-compose run backend django-admin startproject django_app .

これ以降に行うdocker-compose run等のコマンドは、他のターミナルでdocker-compose upを実行して、コンテナを立ち上げた状態で実行してください。

追加設定(docker-compose.yml)

Django実行用のコマンド

次に、先ほど作成したdocker-compose.ymlにcommandを追加します。

services:
  backend:
    container_name: backend
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./.dockervenv/:/backend/.venv/
      - .:/backend/
      - static:/code/static_root
      - media:/code/media
    command: > # add
      bash -c "python manage.py migrate
      && python manage.py runserver 0.0.0.0:8000"
    expose:
      - "8000"

volumes:
  static:
  media:
  pgdata:

これは、Djangoの実行用コマンドです。
毎回docker-compose.ymlを実行した後に、別途Djangoの立ち上げをすることは手間がかかるので、実行するならばdocker-compose.ymlの実行時に一緒に立ち上げてしまいます。

これにより、docker-compose upを実行した際に、Djangoも一緒に起動するようになります。

データベースの設定

データベース関係の設定も書いていきます。
これにより、本来はそれぞれ個別にdockerの設定をしなければならないところ、docker-compse.ymlを利用し、複数のコンテナを一度に設定・実行できるようになります。

今回はデータベース(コンテナ名はdjango_dbとした)の設定を書いていきます。
なお、PostgresQLを使用する予定として、以下のとおり記述します。

なお、dockerのimageとして、postgres:latestを指定し、最新のものを使用する設定としています。

services:
  backend:
    container_name: backend
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./.dockervenv/:/backend/.venv/
      - .:/backend/
      - static:/code/static_root
      - media:/code/media
    command: >
      bash -c "python manage.py migrate
      && python manage.py runserver 0.0.0.0:8000"
    expose:
      - "8000"
    depends_on: # add
      - db
  
  db: # add
    container_name: django_db
    image: postgres:latest
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres

volumes:
  static:
  media:
  pgdata:

backend:コンテナ名
django_app:作成するDjangoのプロジェクト名(-は使えないため_を使用)
なお、プロジェクト名の後に.をつけて実行しているのは、backendディレクトリにdjango_appプロジェクトを作成するためです。

アプリの立ち上げ

以下のコマンドによりdocker経由でDjangoのアプリケーションを立ち上げます。
今回は仮でregisterとして立ち上げます。

docker-compose run backend python manage.py startapp register[アプリ名]

カスタムユーザーモデルの設定

それでは立ち上げたregisterアプリケーションでカスタムユーザーの設定をしていきます。参考にしたのはこちらの記事です。

Userモデルの作成

まずはmodels.pyにDjangoが提供しているAbstractUser modelを継承したUserモデルを定義します。
Userモデルの中身は特に記述しません。

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
  pass

マイグレーションファイルの作成

作成したUserモデルをDjangoに認識させるため、下記のコマンドを実行してマイグレーションファイルを作成します。

docker-compose run backend python manage.py makemigrations

registerを反映させる

作成したマイグレーションファイルを読み込み、反映させるため、下記のコマンドによりマイグレートを実行します。

docker-compose run backend python manage.py migrate

settings.pyへの設定追記

registerを読み込むことと、その他の設定を書いていきます。

追記箇所は「# add」、変更箇所は「# change」として表示しています。
参考にした記事は、先ほどの関連記事と同様ですので、説明は割愛します。

"""
Django settings for django_app project.

Generated by 'django-admin startproject' using Django 4.1.1.

For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""

from pathlib import Path
import os # add

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


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-ex9h$(4=(hplism6%%k1*4&u$pw4)q$l)#h#8buy&vtn&mo_pe'

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

ALLOWED_HOSTS = ['0.0.0.0', 'backend', '127.0.0.1'] # change


# Application definition

INSTALLED_APPS = [
  'register.apps.RegisterConfig', # add
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
]

MIDDLEWARE = [
  'django.middleware.security.SecurityMiddleware',
  'django.contrib.sessions.middleware.SessionMiddleware',
  'django.middleware.common.CommonMiddleware',
  'django.middleware.csrf.CsrfViewMiddleware',
  'django.contrib.auth.middleware.AuthenticationMiddleware',
  'django.contrib.messages.middleware.MessageMiddleware',
  'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'django_app.urls'

TEMPLATES = [
  {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [],
    'APP_DIRS': True,
    'OPTIONS': {
      'context_processors': [
        'django.template.context_processors.debug',
        'django.template.context_processors.request',
        'django.contrib.auth.context_processors.auth',
        'django.contrib.messages.context_processors.messages',
      ],
    },
  },
]

WSGI_APPLICATION = 'django_app.wsgi.application'


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

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

# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
  {
    'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
  },
  {
    'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
  },
  {
    'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
  },
  {
    'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
  },
]


# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/

# add
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static_root'

# add
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

# add
AUTH_USER_MODEL = 'register.User'

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

長くなりますが、念の為、settings.pyは全体を表示させています。

frontendの設定

次に、後々作成予定のフロントエンド側の設定も事前に行っておきます。

以下のコマンドを実行し、まずはフロントエンド作成のディレクトリを作成します。

mkdir app/frontend
touch app/frontend/Dockerfile

Dockerfileの作成

作成したDockerfileに以下のとおり記述します。
現状ではフロントエンドの立ち上げまで持っていくだけですので、最低限の内容で進めます。

FROM node:latest

WORKDIR /frontend
  • FROM node:latest」:最新のnodeのimageをインストールする設定です
  • WORKDIR /frontend」:ワーキングディレクトリの設定です

docker-compose.ymlへの追記

docker-compose.ymlにもフロントエンドに関する情報を追記します。

services:
  backend:
    container_name: backend
    build:
      context: ./backend
      dockerfile: Dockerfile
    volumes:
      - ./backend/.dockervenv/:/backend/.venv/
      - ./backend/:/backend/
      - static:/backend/static_root
      - media:/backend/media
    command: >
      bash -c "python manage.py migrate
      && python manage.py runserver 0.0.0.0:8000"
    ports:
      - 8000:8000
    depends_on:
      - db
  
  db:
    container_name: postgresql
    image: postgres:latest
    environment:
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"
  
  # add
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    volumes:
      - ./frontend/:/frontend/
    command: bash -c "npm start"
    ports:
      - 3000:3000


volumes:
  static:
  media:
  pgdata:

追記した内容はほとんどバックエンドと同様です。
commandportsの部分はバックエンドと異なります。

コンテナのビルド

以下のコマンドでdockerのコンテナを再度ビルドします。
このときバックエンドに加え、データベースとフロントエンドに関するコンテナも併せて立ち上げれます。

docker-compose build --no-cache

フロントエンドの作成

docker-compose.ymlのあるディレクトリで下記のコマンドを実行し、Reactアプリの作成をします。

docker-compose run --rm frontend bash -c "npm install -g create-react-app && create-react-app frontend[フロントエンドアプリ名] --template typescript"
  • frontend[フロントエンドアプリ名]:自分の作成するアプリ名に変えます。ディレクトリ名にもなります。
  • –template typescript:Typescriptの設定でインストールされます。

このコマンドによりnpm installcreate-react-appが実行されます。

再度、dokcer-compose upを実行し、表示されたURLに進み、Reactの立ち上がりが確認できれば、成功です。

最後に

今回はここまでです。

dockerを使用した環境構築とプロジェクトの立ち上げまでを行いました。

他の方法でもできるかもしれませんが、今回はとりあえずこの方法をとったという感じです。
他のベストプラクティスがあれば教えてください。

次回はこの環境をベースに先ほどインストールしていたDjango-Ninjaを試します。

次回もよろしくお願いします。

Django+poetry+dockerで開発

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

はじめまして、ふじです。
Python、Django、FastAPI、React.js、Next.jsを学習している、ずっと文系のプログラミング独学者です。

目次