Flask の Migration を使ってみたのでいろいろメモ。
とりあえず最短で動くまでを構築している。DB は PostgreSQL
フォルダ構成は
├main.py
├config.py
└📁models
├database.py
├user.py
みたいな感じで、models フォルダにモデルを分離した。チュートリアルとかだと、main.py にべた書きしているのが多くて少しだけ手間取った。
database.py にセッション初期化の関数を用意して
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def init_db(app):
db.init_app(app)
config.py には接続情報を用意する。
import os
class DevelopmentConfig:
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = True
SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://{user}:{password}@{host}/{name}'.format(**{
'user': 'postgres',
'password': 'password',
'host': 'localhost:5432',
'name': 'postgres'
})
Config = DevelopmentConfig
そして、メインはこうなる。
from models.user import User
from models.database import db, init_db
app = Flask(__name__)
app.config.from_object('config.Config')
init_db(app)
migrate = Migrate(app, db)
<中略>
if __name__ == "__main__":
app.run()
チュートリアルなどを見ていると db.create_all() という関数を呼んでいるものがあるが、これはマイグレーションをしないで一括で作成してそのままそれをつかう開発の時で、マイグレーションをしたい場合には使えない。マイグレーションで DB を作成したい場合は、コマンドラインで操作する。
その前に、毎回打つのも冗長なので、環境変数に FLASK_APP=manage.py を入れておく。
export FLASK_APP=manage.py
次に、マイグレーションファイルを作成するので初回は初期化する。このコマンドでmigrationsというフォルダが生成される。
flask db init
マイグレーションを実行するとテーブルも作成されます。
flask db migrate
ここで注意。 モデルで外部キーを使っている場合、外部キーの参照先のモデルをインポートしておく必要があります 。あたりまえといえばあたりまえなんだけど、チュートリアルなどで書かれているサンプルだと、同じファイルに全部のモデルが書いてあったりするので意外と気づきにくい。
下記の例だとユーザ(User)が契約(Contract)テーブルに外部キー参照を持っているので、contract をインポートする必要がある。
from models.database import db
from models.contract import Contract #←これが必要だよ!!!!!
class User(db.Model):
__tablename__ = 'User'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
create_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
update_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
contract_id = db.Column(db.Integer, db.ForeignKey('Contract.id'))
email = db.Column(db.String(255), nullable=True)
def __init__(self, sumaregi_user_id, contract_id):
self.contract_id = contract_id
その他メモ
文字数制限のないテキスト型
Text というのがある
email = db.Column(db.Text, nullable=True)
型を修正してマイグレーションしても反映されないとき
Migrate に compare_type=True オプションを付ける必要がある。
migrate = Migrate(app, db, compare_type=True)