プログラミング

VPSを使ってウェブアプリを作りたい3

はじめに

前回→VPSを使ってウェブアプリを作りたい2(Github ActionsでCI/CD)

もう少し開発環境を整えていく。

  • 環境管理.envpython-dotenv でシークレット/設定を一元管理
  • DBマイグレーション:SQLAlchemy + Alembic を導入(Flask-SQLAlchemy とFlask-Migrate)
  • CI/CD拡張:CI に Linter(flake8 or black)、型チェック(mypy)、Coverage レポート   を追加。CD に「マイグレーション実行」「ヘルスチェック」「ロールバック条件」ステップを追加
  • ドキュメント整備:README に「開発手順」「CI/CD フロー」「環境変数一覧」を明記

環境管理とDBマイグレーション

1 .env.env.example を用意する

プロジェクトルートに .env を作成し、機密情報や環境ごとに変わる設定だけを置く。
gitには上げない。 PostgreSQLインストールはこちら
# .env
FLASK_ENV=development
SECRET_KEY="ランダムな長い文字列"
DATABASE_URL=postgresql://myapp_user:password@localhost:5432/myapp_db
同じく 雛形としてキー名だけのgit管理用の.env.example を作る
# .env.example
FLASK_ENV=
SECRET_KEY=
DATABASE_URL=
.gitignore に以下を追加して、.env は Git管理から外す。.env.exampleはGit管理のまま
.env
!.env.example

必要ライブラリのインストール

pip install python-dotenv Flask-SQLAlchemy Flask-Migrate psycopg2-binary
  • python-dotenv.env から環境変数をロードできる
  • Flask-SQLAlchemy … SQLを使わずにDBを操作できるSQLAlchemyのFlask連携版
  • Flask-Migrate … DB変更履歴を管理できるAlembicのFlask連携版
  • psycopg2-binary … PostgreSQL ドライバ
ライブラリを追加したら、requirements.txtに追加しておく
pip freeze > requirements.txt

.env の読み込みテスト

環境変数を正しく読み込めるか確認
tests/test_env.pyを作って以下を入力
import os
from dotenv import load_dotenv, find_dotenv


def test_env_loading():
    # プロジェクトルートの .env を読み込む
    dotenv_path = find_dotenv(".env", raise_error_if_not_found=True)
    load_dotenv(dotenv_path)

    # DATABASE_URL が設定されていることを確認
    assert os.getenv("DATABASE_URL") is not None
    # 必要なら値の形式チェック(postgresql://で始まっている文字列かチェック)
    assert os.getenv("DATABASE_URL").startswith("postgresql://")
pytestでチェック
python -m pytest

app.py を修正

 

import os
from dotenv import load_dotenv
from flask import Flask

# 1) .env をロード
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, ".env"))

app = Flask(__name__)
# 2) 設定を環境変数から
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "change-me")
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

# 3) ORM とマイグレーションを初期化
from flask_sqlalchemy import SQLAlchemy
from flask_migrate      import Migrate
db      = SQLAlchemy(app)
migrate = Migrate(app, db)

@app.route("/")
def index():
    return "Hello, myapp!"

if __name__ == "__main__":
    app.run(debug=True)

モデルファイルを用意

データベースに格納する情報のモデル(規格のようなもの)を設定する。

# models.py
from app import db
from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model):
    id       = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, nullable=False)
    pwd_hash = db.Column(db.String(128), nullable=False)


    # 平文のパスワードpwをハッシュ(暗号)化して保存
    def set_password(self, pw):
        self.pwd_hash = generate_password_hash(pw)

    # 入力された平文のパスワードpwが保存してあるハッシュと一致するかチェック
    def check_password(self, pw):
        return check_password_hash(self.pwd_hash, pw)
  • primary_key=True:主キーとして自動採番
  • unique=True:同じユーザー名を二度登録できない一意制約
  • nullable=False:空(NULL)を禁止

app.pyにモデルを読み込むコードを記入

import os
from dotenv import load_dotenv
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

# .env を読み込む
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, ".env"))

# Flask アプリの生成と設定
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "change-me")
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

# ORM/マイグレーション用オブジェクトを初期化
db = SQLAlchemy(app)
migrate = Migrate(app, db)

#------------ここから追加分---------
# models.py を読み込む
import models
#------------ここまで追加分---------


@app.route("/")
def index():
    return "Hello, myapp!"

if __name__ == "__main__":
    app.run(debug=True)

Flask CLI の設定

ターミナルでflaskコマンドを使うために設定を読み込む。
.envに記入済みの場合は無くてもいいかもしれない
export FLASK_APP=app.py
export FLASK_ENV=development

マイグレーション初期化

データベースの履歴管理のためのmigrateフォルダの初期設定
flask db init

プロジェクト直下に migrations/ ディレクトリが作成され、中に alembic.inienv.py などが生成される

初回マイグレーションの作成・適用
flask db migrate -m "initial schema"
flask db upgrade
models.pyの定義に沿ってカラムが作られる。

データベースが正しく作成されているかチェック

psql -d myapp_db -c "\dt"

 

モデルが循環参照になっていてうまくいかない時

モデルの ForeignKey 定義に use_alter=True を指定すると、Alembic が
  1. テーブル本体をまず作成
  2. その後で ALTER TABLE … ADD CONSTRAINT … で FK を追加
という 2 ステップに分けてマイグレーションスクリプトを生成してくれる

 

 

 

ABOUT ME
いなさく
住んでる家が崩れそうなので、建て替え費用をまかなうために 副業をがんばるサラリーマン
ブログランキング・にほんブログ村へ

COMMENT

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

CAPTCHA