概要
alembicでマイグレーションファイル作成する際に行う
alembic revision --autogenerate -m "hogehoge"
このコマンドを実行することで、modelとSQLAlchemyでで定義したmodelの状態とDBの状態との差分を検知して、マイグレーションファイルが自動生成される。
しかし、何回やってもtableがdropされるコードが出来上がる。
def upgrade() -> None:
op.drop_table('users')
op.drop_table('posts')
def downgrade() -> None:
op.create_table('users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('email', sa.String(), nullable=True),
)
op.create_table('posts',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(), nullable=False),
sa.Column('content', sa.String(), nullable=True),
)
ちなみに手書きでコード書いても、add_columnとかはDBに反映されなかった。
解決策
こういったautogenerateが検知されなかったり、
alembic upgrade head
をしてもDBに反映されなかったり、といった原因は往々にして
env.pyの
target_metadata=Base.metadata
にあります。
これはmodelの情報をtarget_metadataに渡すためのコードです。
models.pyが複数あると、Baseクラスのmetadataを結合させる必要が出てくる。
# modelが複数ある場合、importしてくる
from users import models as users_model
from posts import models as posts_model
def combine_metadata(*args):
m = MetaData()
for metadata in args:
for t in metadata.tables.values():
t.tometadata(m)
return m
target_metadata = combine_metadata(users_model.Base.metadata, posts_model.Base.metadata)
modelは全てtarget_metadataに入れてあげようねって話でした。
余談
型定義の変更はautogenerateで検知されないらしい。
検知したい時は
compare_type=Trueを追加する
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True, #同じカラム名でも型の変更を検知する
)
参考
https://qiita.com/orange634nty/items/dcbcc10eb14f5e10f398/
http://liuhongjiang.github.io/hexotech/2015/10/14/alembic-support-multiple-model-files/