Edited at

Flask + SQLAlchemyプロジェクトを始める手順

いつも行っていることをまとめる。

参考にするドキュメント

今回の利用した環境は以下の通り。


  • MacOS 10.13.3

  • Python 3.6.3

  • flask 0.12.2

  • flask-sqlalchemy 2.3.2

  • PyMySQL 0.8.0

  • SQLAlchemy 1.2.2


必要なライブラリをインストールする


  • flask

  • SQLAlchemy

  • flask-sqlalchemy

  • pymysql

をインストールする。

$ pip install flask SQLAlchemy flask-sqlalchemy PyMySQL


アプリ初期構築

アプリの初期構築を行う。

Flaskは自由度が高いのでアプリのディレクトリ構成は様々な形を取ることができるが、以下はその一例。この例に沿って以下話を進める。

├── flask_sample

│ ├── app.py
│ ├── config.py
│ └── database.py
└── run.py


  • flask_sample/database.py

"""FlaskアプリがSQLAlchemyを使えるようにするための初期化"""

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def init_db(app):
db.init_app(app)


  • flask_sample/config.py

"""FlaskのConfigを提供する"""

import os

class DevelopmentConfig:

# Flask
DEBUG = True

# SQLAlchemy
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{user}:{password}@{host}/flask_sample?charset=utf8'.format(**{
'user': os.getenv('DB_USER', 'root'),
'password': os.getenv('DB_PASSWORD', ''),
'host': os.getenv('DB_HOST', 'localhost'),
})
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False

Config = DevelopmentConfig

※1 上記の SQLALCHEMY_DATABASE_URI は、DriverにPyMySQLを利用した場合の書き方になっている。PyMySQLとは別のDriverを用いる場合は別の設定にする必要がある。詳しくはリンク先ページ参照。 http://docs.sqlalchemy.org/en/latest/dialects/mysql.html

※2 今回Database名を flask_sample としている。当然MySQLからCREATE DATABASE文を使ってDatabaseを先に作っておく必要がある。(Databaseの作成方法は割愛)


  • flask_sample/app.py

"""flask appの初期化を行い、flask appオブジェクトの実体を持つ"""

from flask import Flask

from flask_sample.database import init_db

def create_app():
app = Flask(__name__)
app.config.from_object('flask_sample.config.Config')

init_db(app)

return app

app = create_app()


  • run.py

from flask_sample.app import app

if __name__ == '__main__':
app.run()

このアプリを起動する場合は、以下のコマンドを実行する。

$ python run.py

あるいは環境変数FLASK_APPを定義してflaskコマンドを利用することでもアプリを起動することができる。

$ FLASK_APP=run.py flask run

これでFlaskでSQLAlchemyを利用する基本的な準備は整った。


Modelを一つ作ってみる

実際にModelクラスを一つ作ってみることにする。


Modelクラスの定義

以下のように flask_sample/models 以下を用意する。

flask_sample

├── app.py
~
└── models
├── __init__.py
└── models.py


  • flask_sample/models/models.py

from datetime import datetime

from flask_sample.database import db

class User(db.Model):

__tablename__ = 'users'

id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.now)
updated_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)


  • flask_sample/models/__init__.py

from .models import User

__all__ = [
User,
]

そして、appがロードされた時にこのUserクラスもloadされるように、flask_sample/app.py内でUserクラスをimportするようにする。

from flask import Flask

from flask_sample.database import init_db
import flask_sample.models

...


テーブルの作成


※2019/01/03追記

この直後に説明する Flask-Migrate を使ったMigrationを実施する場合は、ここで説明している db.create_all() を使ったテーブルの作成は行うべきではありません。

Flask-Migrate ではテーブルの状態管理をしており、 Flask-Migrate を使わずにテーブル作成した場合、未知の状態を与えてしまうためです。もし、 Flask-Migrate を利用する予定の場合はこの項の説明を読み飛ばして次の説明を読み進めることをおすすめします。

参考issue

https://github.com/miguelgrinberg/Flask-Migrate/issues/173


Modelクラスを用意したら、次にDatabaseにテーブルを作成する。

テーブルを作成するには SQLAlchemy.create_all() を呼び出す。これでimportされているModelクラスのテーブルが全て作成される。

$ FLASK_APP=run.py flask shell

Python 3.6.3 (default, Jan 8 2018, 18:42:55)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
App: flask_sample.app [debug]
Instance: ~/flask-sample/instance
>>> from flask_sample.database import db
>>> db.create_all()

これで users テーブルが作成された。


migrationを行うには

直前の手順で、定義しているModelクラスに関するテーブルが作成されたわけだが、都度手動で db.create_all() を呼び出してテーブルを定義するには少し面倒が多く、きちんとschemaのバージョン管理を行うことも含めてMigrationの導入を行う。

Flask + SQLAlchemy でMigrationを行うには Flask-Migrate を使うと便利。


Flask-Migrateのインストール

pipでインストール可能。

$ pip install Flask-Migrate


Flask-Migrateを使う

Flask-Migrateを使うには、flask_migrate.Migrate をflaskオブジェクトと flask_sqlalchemy.SQLAlchemy オブジェクトを食わせることでFlask-MigrateのCLIコマンドを使うことが可能になる。以下は上記までのサンプル上でFlask-Migrateを使う場合の例。


  • flask_sample/database.py

"""FlaskアプリがSQLAlchemyとFlask-Migrateを使えるようにするための初期化"""

from flask_sqlalchemy import SQLAlchemy

from flask_sample.database import init_db

from flask_migrate import Migrate # 追加

db = SQLAlchemy()

def init_db(app):
db.init_app(app)
Migrate(app, db) # 追加

こうした後では flask db コマンドが利用可能になる。

$ FLASK_APP=run.py flask db init


Flask-Migrateのコマンド例

最低限のコマンド例を示す。

https://flask-migrate.readthedocs.io/en/latest/#command-reference

こちらにコマンドリファレンスがあるので、これで利用可能なコマンドの全貌がわかる。

※以下のコマンド例は環境変数 FLASK_APP を適切に設定している場合における場合。


初期化

$ flask db init

migrationsディレクトリが作成され、その中で必要なファイルが設置される。


migrationファイルの作成

$ flask db migrate

modelクラスの定義を見て、差分をmigrationファイルとして作成する。(まだmigrationの適用はされない)


migrationの実行

$ flask db upgrade

未実行のmigrationを実行する。


migrationのrollback

$ flask db downgrade

一つ前のバージョンに戻す。


まとめ


  • Flaskアプリの初期構築

  • Flask-SQLAlchemyの使い方(Model定義)

  • Flask-Migrateの使い方

を簡単に説明した。これでベーシックなFlask + SQLAlchemyを使ったアプリケーション構築のための準備が整った。

追加でこれをしていくといいよ、というのがあればどしどし。