原文は私が書いてるBlogにのってます。よろしくおねがいします
http://soup01.com/ja/2018/07/24/flaskdb-migrate/
今回はFlask-Migrateの使え方についてメモします。まずFlask-Migrateはなんなのか公式ドキュメントをみてみると…
Flask-Migrate is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations are made available through the Flask command-line interface or through the Flask-Script extension.
うんうん、いわゆるFlaskのExtensionの一つでSQLAlchemyのデータベースをマイグレーションを簡単にできるってことですね〜あとこの操作はFlaskのコマンドラインかFlask-Script Extensionかのことかな。まずFlask-Migrateをインストールしましょう。
pip install Flask-Migrate
次はFile構成:
- Web
- Manger.py
いまのFile構成はこんな感じですね、WebのFolderの下にManger.pyがあります。Manger.pyはどんなコードが入ってるかどういうど…
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate,MigrateCommand
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db=SQLAlchemy(app)
migrate=Migrate(app,db)
manager=Manager(app)
manager.add_command('db',MigrateCommand)
class Person(db.Model):
id=db.Column(db.Integer,primary_key=True)
name=db.Column(db.String(20))
email=db.Column(db.String(120))
address=db.Column(db.String(120),nullable=False)
tel=db.Column(db.String(20),nullable=False)
password=db.Column(db.String(60),nullable=False)
spare1=db.Column(db.String(21))
if __name__=='__main__':
manager.run()
いまはFolderがDBさえ入ってはい状態でManger.pyを走ってみよう。
$ python Manger.py db init
Terminalでいろいろなメッセージが出てきて、終わったらFile構成がこうなります。
- Web
- Manger.py
- migrations←
migrationsというFolderが増えてきました。じゃ次はのコマンドを走りましょう。
$ python Manger.py db migrate
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'person'
Generating /Users/user/Google Drive/Web/migrations/versions/c1cc8fa0d2c6_.py ... done
って感じですね。ほ、私が新しいTableを追加してたと気ついてたね〜そしてmigrations/versions/の中に一つのpyスクリプトが追加された。じゃこのc1cc8fa0d2c6.pyがなにが入ってるですか?
"""empty message
Revision ID: c1cc8fa0d2c6
Revises:
Create Date: 2018-07-24 05:30:05.947666
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c1cc8fa0d2c6'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table('person',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=20), nullable=True),
sa.Column('email', sa.String(length=120), nullable=True),
sa.Column('address', sa.String(length=120), nullable=False),
sa.Column('tel', sa.String(length=20), nullable=False),
sa.Column('password', sa.String(length=60), nullable=False),
sa.Column('spare1', sa.String(length=21), nullable=True),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
op.drop_table('person')
Manger.pyの中に定義されたClassがここでDBに入れるってわけですね。じゃ最後のコマンドを走りましょう。
$ python Manger.py db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> c1cc8fa0d2c6, empty message
- Web
- Manger.py
- migrations
- test.db←
おお、DBが作成されました!じゃ、最後はsqlite3コマンドで確認しましょうか。
sqlite3 test.db
sqlite>.schema
CREATE TABLE person (
id INTEGER NOT NULL,
name VARCHAR(20),
email VARCHAR(120),
address VARCHAR(120) NOT NULL,
tel VARCHAR(20) NOT NULL,
password VARCHAR(60) NOT NULL,
spare1 VARCHAR(21),
PRIMARY KEY (id)
);
OK、それで大丈夫だね。次はManger.pyにもうひとつのTableを追加しましょう。
class tempClass(db.Model):
id=db.Column(db.Integer,primary_key=True)
title=db.Column(db.String(20))
そしてもう一度コマンドを走ります。
$ python Manger.py db migrate
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'temp_clasee'
Generating /Users/user/Google Drive/Web/migrations/versions/6c77edaef8c4_.py ... done
$ python Manger.py db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade c1cc8fa0d2c6 -> 6c77edaef8c4, empty message
どうやらうまくいけそうですね。
sqlite3 test.db
sqlite>.schema
CREATE TABLE person (
id INTEGER NOT NULL,
name VARCHAR(20),
email VARCHAR(120),
address VARCHAR(120) NOT NULL,
tel VARCHAR(20) NOT NULL,
password VARCHAR(60) NOT NULL,
spare1 VARCHAR(21),
PRIMARY KEY (id)
);
CREATE TABLE temp_clasee (
id INTEGER NOT NULL,
title VARCHAR(20),
PRIMARY KEY (id)
);
うん、それは大丈夫だね!
実はいくつの問題がありますが…
- Tableの内容が修正されてMigrateしてもなにも変わらない。
- ネットでみたらどうやら100%修正したものをDetectできるわけでもないらしいのでmigrateのコマンド走ったあとは必ずそのとき作成されたpyを一回みること。
- nullable=Falseのコラムがupgradeコマンド走るときはエラー出る問題
- うん…これはわかりません。いまはとりあえずnullableを入れないで、DBがマイグレーション終わったら手動でSqliteコマンドでCOPYー>修正ー>貼り付けって感じですね。参考Link:sqlite3 - Modify Sqlite Table Column NOT NULL to NULL - Stack Overflow
それじゃねー