見出し画像

Djangoを使ったWebアプリの作り方 ④Docker+PostgreSQL編

Djangoでアプリ開発をする際、データベースはデフォルトでSQLite3が選ばれます。でも、少し実践的な使い方を想定する場合、PostgreSQLに変更する場合が多いです。

デフォルトのデータベースとしてSQLite3が選ばれている理由は、簡単さと手軽さからですが、デメリットもあります。

以下では、SQLite3とPostgreSQLの違いに着目し、PostgreSQLが良い理由をわかりやすく説明し、具体的な設定例を説明します。

1. スケーラビリティ

SQLite3: 小規模なアプリケーションや開発環境には適していますが、データが増えたり、同時に多くのユーザーがアクセスしたりすると、動きが遅くなることがあります。

PostgreSQL: 大規模なデータベースを扱うことができ、同時接続数が多くても安定したパフォーマンスを提供します。例えば、ユーザーが数百人同時にアクセスするようなウェブアプリケーションでも、PostgreSQLが安定して動き続けます。データが増えても、性能が落ちにくいのです。

2. 機能の豊富さ

SQLite3: 基本的な機能はありますが、複雑なデータ型やクエリの処理には限界があります。例えば、シンプルなデータの保存や取得には問題ありませんが、複雑なデータの管理や高度な検索には限界があります。

PostgreSQL: 複雑なデータ型(例:JSON、配列)や高度なクエリ(例:ウィンドウ関数、CTE)をサポートしており、データの管理が柔軟です。たとえば、地理情報システム(GIS)を扱うアプリケーションでは、PostgreSQLの拡張機能であるPostGISが非常に役立ちます。

3. データの整合性

SQLite3: トランザクションの管理は基本的なものですが、同時に複数の書き込みが行われると競合が発生することがあります。

PostgreSQL: トランザクションの管理が優れており、複数の人が同時にデータを扱っても、データの正確さを保つことができます。例えば、大規模なオンラインショップで、多くのユーザーが同時に商品を購入しても、データがしっかり管理されます。

4. 具体的な設定例

SQLiteからPostgreSQLへの変更手順を以下に示します。以下参考サイトで作成した、Docker対応したDjangoプロジェクトから実施していきます。

4.1 必要なパッケージのインストール:

PostgreSQLを使用するためには、psycopg2というライブラリをインストールします。これにより、DjangoがPostgreSQLと連携できるようになります。
今回は仮想環境にpipenvを使用しているので、pipenvでpsycopg2をインストールします。

pipenv install psycopg2

インストールされると、Pipfile.lockにpsycopg2が追加されます。

Pipfile.lockファイル画像

4.2 PostgreSQLデータベースの設定:

PostgreSQLで新しいデータベースを作成するための設定をします。データベースを作成する際に、パスワードなど知られたくない秘密情報も設定する必要があります。こんな場合、.envファイルを使って設定します。
.envファイルには以下内容を記載します。

POSTGRES_NAME=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=db
POSTGRES_PORT=5432

'''
# ディレクトリ構成
├── Django_Project                   # << カレントディレクトリ
    ├── manage.py
    ├── db.sqlite3
    ├── Pipfile
    ├── Pipfile.lock
    ├── docker-compose.yml
    ├── .env              # << 追加
    ├── containers/
    |   ├── django
    |      ├── Dcokerfile
    |      ├── entorypoint.sh
    │
    ├── mysite/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    │   └── asgi.py
    │
    └── myapp/
        ├── migrations/
        ├── templates/
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── forms.py
        ├── models.py
        ├── tests.py
        ├── urls.py
        └── views.py

# コードの説明
POSTGRES_NAME=postgres
>>接続するデータベースの「名前」を指定します。
 ここでは、データベース名が「postgres」に設定されています。

POSTGRES_USER=postgres
>>データベースに接続するための「ユーザー名」を指定します。
 ここでは、「postgres」というユーザー名を使用しています。

POSTGRES_PASSWORD=postgres
>>ユーザーがデータベースにアクセスするための「パスワード」を指定します。
 ここでは、「postgres」というパスワードが設定されています。

POSTGRES_HOST=db
>>データベースがどこで動いているかを指定します。
 db というのは、Dockerのデータベースコンテナの名前です。
 ローカルで動かしている場合は localhost になります。

POSTGRES_PORT=5432
>>データベースが利用している「通信ポート番号」を指定します。
 (PostgreSQL のデフォルトポートは 5432 なので、そのままこの番号を使っています。)
'''

また、.envファイルは秘密情報となりますのでgitの管理対象外とします。そのため.gitignoreを作成して以下内容を追記します。

# Environments
.env

'''
# ディレクトリ構成
├── Django_Project                   # << カレントディレクトリ
    ├── manage.py
    ├── db.sqlite3
    ├── Pipfile
    ├── Pipfile.lock
    ├── docker-compose.yml
    ├── .env
    ├── .gitignore                    # << 追加
    ├── containers/
    |   ├── django
    |      ├── Dcokerfile
    |      ├── entorypoint.sh
    │
    ├── mysite/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    │   └── asgi.py
    │
    └── myapp/
        ├── migrations/
        ├── templates/
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── forms.py
        ├── models.py
        ├── tests.py
        ├── urls.py
        └── views.py

# コードの説明
.env
>>.env ファイルは「環境変数を保存する専用ファイル」です。
 .envをgitの管理対象から除外しています。
'''

.gitignoreファイルに記載する内容は、使用する言語(python)やフレームワーク(Django)で共通するため、よしなに記載内容を教えてくれる便利なサイト(gitignore.io)もあります。以下サイトを参考に設定してください。

4.3 Djangoの設定ファイルを変更:

settings.pyファイルを開き、データベース設定を以下のように変更します。
また、.envファイルの記載内容を取得するため、osライブラリもインポートします(os.environ.get関数で、.envに記載した内容を取得できます)。

from pathlib import Path
import os                       # <<追加

# --------------------------
# <省略>
# --------------------------

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",        # << 修正
        "NAME": os.environ.get("POSTGRES_NAME"),          # << 修正
        "USER": os.environ.get("POSTGRES_USER"),          # << 追加
        "PASSWORD": os.environ.get("POSTGRES_PASSWORD"),  # << 追加
        "HOST": os.environ.get("POSTGRES_HOST"),          # << 追加
        "PORT": os.environ.get("POSTGRES_PORT"),          # << 追加
    }
}

# --------------------------
# <省略>
# --------------------------

'''
# ディレクトリ構成
├── Django_Project                   # << カレントディレクトリ
    ├── manage.py
    ├── db.sqlite3
    ├── Pipfile
    ├── Pipfile.lock
    ├── docker-compose.yml
    ├── .env
    ├── .gitignore 
    ├── containers/
    |   ├── django
    |      ├── Dcokerfile
    |      ├── entorypoint.sh
    │
    ├── mysite/
    │   ├── __init__.py
    │   ├── settings.py                   # << 修正
    │   ├── urls.py
    │   └── wsgi.py
    │   └── asgi.py
    │
    └── myapp/
        ├── migrations/
        ├── templates/
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── forms.py
        ├── models.py
        ├── tests.py
        ├── urls.py
        └── views.py
'''

'''

# コードの説明
import os
>>.Python の標準ライブラリ os をインポートしています。
 環境変数を扱うために必要です。
 ここでは os.environ.get() を使って .env ファイルやシステム環境から値を取得しています。


"ENGINE": "django.db.backends.postgresql"
>>Django が使用するデータベースエンジンを指定します。
 django.db.backends.postgresql は PostgreSQL データベースを使うことを意味します。

"NAME": os.environ.get("POSTGRES_NAME")
>>接続するデータベースの「名前」を指定します。
 ここでは、環境変数 POSTGRES_NAME に設定された値を取得しています。

"USER": os.environ.get("POSTGRES_USER")
>>データベースにアクセスするための「ユーザー名」を指定します。
 環境変数 POSTGRES_USER から値を取得します。

"PASSWORD": os.environ.get("POSTGRES_PASSWORD")
>>データベースに接続する際に必要な「パスワード」を指定します。
 環境変数 POSTGRES_PASSWORD から値を取得します。

"HOST": os.environ.get("POSTGRES_HOST")
>>データベースがどこに存在しているか(ホスト名)を指定します。
 環境変数 POSTGRES_HOST から値を取得します。
 ローカル環境なら通常は localhost、Docker なら db などになります。

"PORT": os.environ.get("POSTGRES_PORT")
>>これは設定項目の名前です。
 環境変数 POSTGRES_PORT から値を取得します。
 「ポート番号」を指定するための項目です。
'''

4.4 PostgreSQLコンテナの設定:

今回は、Dockerを使って環境を構築しているため、postgreSQLもDockerを使って設定していきます。
まずはpostgreSQL用のDockerfile作成します。
以下内容を./containsers/postgres/Dockerfileに記載します。

FROM postgres:16.1

'''
# ディレクトリ構成
├── Django_Project                   # << カレントディレクトリ
    ├── manage.py
    ├── db.sqlite3
    ├── Pipfile
    ├── Pipfile.lock
    ├── docker-compose.yml
    ├── .env
    ├── .gitignore 
    ├── containers/
    |   ├── django
    |      ├── Dcokerfile
    |      ├── entorypoint.sh
    |   ├── postgres                        # << 作成
    |      ├── Dcokerfile                   # << 作成
    │
    ├── mysite/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    │   └── asgi.py
    │
    └── myapp/
        ├── migrations/
        ├── templates/
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── forms.py
        ├── models.py
        ├── tests.py
        ├── urls.py
        └── views.py

# コードの説明
FROM postgres:16.1
>>FROM: Dockerfile の中で使われる命令で、「このイメージ(テンプレート)をベースに新しいコンテナを作ります」という意味です。
 postgres:16.1: PostgreSQL(ポストグレス)というデータベースの公式イメージを指定しています。
 この場合、バージョンは 16.1 です。

'''

次に、docker-compose.ymlにも、Postgresqlの設定を追記します。
追記する内容は以下です。

services:
  db:                                                    # << 追加
    container_name: postgres                             # << 追加
    
    build:                                               # << 追加
      context: .                                         # << 追加
      dockerfile: ./containers/postgres/Dockerfile       # << 追加

    volumes:                                             # << 追加
      - db_data:/var/lib/postgresql/data                 # << 追加

    ports:                                               # << 追加
      - 5432-5432                                        # << 追加

    env_file:                                            # << 追加
      - .env                                             # << 追加


  app:
    container_name: app

    build:
      context: .
      dockerfile: ./containers/django/Dockerfile

    volumes:
      - .:/code

    ports:
      - 8000:8000

    command: sh -c "/usr/local/bin/entrypoint.sh" 

    env_file:                                            # << 追加
      - .env                                             # << 追加

    depends_on:                                          # << 追加
      - db                                               # << 追加

volumes:                                                 # << 追加
  db_data:                                               # << 追加


'''
# ディレクトリ構成
├── Django_Project                   # << カレントディレクトリ
    ├── manage.py
    ├── db.sqlite3
    ├── Pipfile
    ├── Pipfile.lock
    ├── docker-compose.yml                 # << 修正
    ├── .env
    ├── .gitignore 
    ├── containers/
    |   ├── django
    |      ├── Dcokerfile
    |      ├── entorypoint.sh
    |   ├── postgres
    |      ├── Dcokerfile
    │
    ├── mysite/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    │   └── asgi.py
    │
    └── myapp/
        ├── migrations/
        ├── templates/
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── forms.py
        ├── models.py
        ├── tests.py
        ├── urls.py
        └── views.py

# コードの説明
db:
>>アプリケーションを構成するdbコンテナを定義しています。

container_name: postgres
>>このコンテナに「postgres」という名前を付けます。
 Docker 内部でこの名前を使って他のサービスからアクセスできます。
    
build:
>>Dockerfile(コンテナを作る設計図)がどこにあるかを指定します。

context: .
>>現在のディレクトリを基準にファイルを探します。

dockerfile: ./containers/postgres/Dockerfile
>>PostgreSQL 用の Dockerfile が ./containers/postgres/Dockerfile にあることを示します。

volumes:
>>ホスト(自分のパソコン)のフォルダをコンテナ内にマウント(共有)します。

- db_data:/var/lib/postgresql/data
>>データベースのデータを保存する場所をコンテナ外に保持します(データ永続化のため)。

ports:
>>ホスト(自分のPC)とコンテナ間で通信するためのポートを指定します。

- 5432-5432
>>PostgreSQL のデフォルトポート 5432 を使います。

env_file:
>>.env ファイルを読み込んで環境変数(データベースの設定情報など)をコンテナ内で使えるようにします。

- .env
>>.env ファイルを読み込みます。

depends_on:
  - db
>>このコンテナを起動する前に db サービス(PostgreSQL)を起動するよう指定します。

volumes:
>>データを永続化する仕組み(コンテナを削除してもデータが消えないようにする)を定義しています。

db_data:
>>データベースのデータを永続化するための領域を定義しています。
  これにより、コンテナを削除してもデータが消えません。
'''

4.5 マイグレーションの実行:

モデルを定義した後、データベースにテーブルを作成するためには、マイグレーションを実行する必要があります。今回は、コンテナ起動後にentrypoint.shで実行する設定をしているため、変更なしでOKです。

4.6 コンテナのビルドと起動:

以下のコマンドを実行して、Dockerイメージをビルドし、コンテナを起動します。

docker-compose up -d --build

'''
# コードの説明
docker-compose up:
>>Docker Composeで定義されたサービス(コンテナ)を起動します。

-d(デタッチドモード):
>>コンテナをバックグラウンドで実行します。
 つまり、ターミナルを占有せずに他の作業ができます。

--build:
>>各サービスのDockerイメージをビルドしてから起動します。
 Dockerfileやコードに変更があった場合、新しいイメージを作成します。
'''

以上を行うと、SQLiteからPostgreSQLに切り替えることができます。
ユーザー数が多いアプリケーションや、データの整合性が重要な場合には、PostgreSQLの使用が推奨されます。

5. まとめ

SQLiteとPostgreSQLの違い、PostgreSQLの設定方法について記載しました。作業自体はそれほど大変ではなかったと思います。


いいなと思ったら応援しよう!