2020年7月17日金曜日

一度削除してしまったテーブルを Flask-Migrate で再作成する方法

概要

過去に Flask-Migrate でテーブルの変更履歴管理を行う方法を紹介しました
テストなどでテーブルを削除してしまった場合に upgrade コマンドだと再作成できないようだったので再作成する方法を考えてみました

環境

  • macOS 10.15.5
  • MySQL 8.0.19
  • Python 3.8.3
  • Flask-Migrate 2.5.3

一度テーブルを削除して再度作成するには

  • mysql -u root test -e "drop table user;"

こんな感じでテーブルを削除してしまった場合に再度 head の定義にあるテーブルを作成する方法を紹介します

方法その1: 再度 migrate する

migrate -> upgrade と順番に実行すると再度最新の定義でテーブルを作成することができます
また create table の定義がかかれているので他の環境に展開する場合はこのコミットを使えば upgrade だけで作成できます
しかしこの方法だと無駄なコミットが増えてしまいます

  • FLASK_APP=my_app pipenv run flask db migrate -m "Recreate table"
  • FLASK_APP=my_app pipenv run flask db upgrade head

方法その2: flask shell を使って db.create_all() をコールする

  • FLASK_APP=my_app pipenv run flask shell

で python のインタラクティブモードに入ったら

from my_app.database import db
db.create_all()

を実行すればテーブルが作成されます
これ自体は Flask-SQLAlchemy の機能を使って行っています
これであればコミットを作成することなく最新の定義でテーブルを作成できます

方法その3: alembic_version も drop して upgrade する

alembic_version テーブルに現在適用されているバージョンが記載されているのでこれを削除して upgrade します

  • mysql -u root test -e "drop table alembic_version;"
  • FLASK_APP=my_app pipenv run flask db upgrade head

これが一番王道だと思います
が注意しなければいけないのはもし手動で drop table してその後 Recreate の migrate をしてしまった場合は Recreate の migrate が適用されません
なぜなら Recreate のマイグレートには手動で削除した drop table の定義が書かれていないため user テーブルがすでに存在する状態で再度 create table しようとします
なのでもしそのような状態になったら再度手動で drop table user してから upgrade するかマイグレート用のスクリプトファイルを直接編集してテーブル度ドロップする定義を追加してから upgrade すれば OK です

おまけ: コミットメッセージを変更するには

  • pipenv run flask db edit head

おまけ: コミットを削除するには

もし history が以下のようになっている場合はそれに対応するファイルを削除すれば OK です

2036fa9f973c -> b966967378d7 (head), Recreate table 68be7c84addb -> 2036fa9f973c, 2 <base> -> 68be7c84addb, 1
  • rm migrations/versions/b966967378d7_recreate_table.py

最後に

普通に別のデータベースにマイグレートする場合は upgrade すれば大丈夫なはずです
が、ローカルなどで開発しているときにテーブルを手動で削除した場合には少し工夫が必要な感じになります
それでも alembic_version を削除して upgrade するのが一番簡単かなと思います
ただマイグレートコミットが矛盾するような履歴になってしまうと upgrade 時にエラーになるので注意しましょう
もしそうなった場合は直接マイグレートスクリプトファイルを編集するか再度リポジトリを作成し直しでも良いかなと思います

0 件のコメント:

コメントを投稿