alembic + SQLModelでデータベースをマイグレーションする
バックエンドをPython + MySQL(PlanetScale) + SQLModel で開発しており、データベースマイグレーションにはalembicを使っています。alembicは、SQLAlchemy の開発者である Mike Bayer さんが作ったツールです。alembicを使う手順をまとめます。
alembicインストール
poetry add alembic --group dev
alembic init alembic
alembic設定ファイルをSQLModel向けに修正
設定ファイル/alembic/env.py
と、自動生成されるスクリプトのテンプレートファイル/alembic/script.py.mako
を修正します。
env.py
SQLModelのインポートを追加します。
from sqlmodel import SQLModel
21行目あたりのtarget_metadataをSQLModelに切り替えます。
target_metadata = None
->
target_metadata = SQLModel.metadata
alembic/script.py.mako
SQLModelのインポートを追加します。
import sqlmodel
接続先データベースの変更
設定ファイル /alembic.ini
64行目あたりに書かれている接続先データベースを変更します。
ローカル開発環境
sqlalchemy.url = sqlite:///test.db
MySQL(PlanetScale)
sqlalchemy.url = mysql+pymysql://127.0.0.1:3306/dbname
新規テーブルの登録
新しくテーブルを作りたい場合は、env.py
にSQLModelテーブルクラスのインポートを追加します。
from common.model.hoge import Hoge
__all__ = ["Hoge"]
マイグレーションファイルの自動生成
versions/
の中にマイグレーションファイルが生成されます。自動生成では対応できていない場合があるので、必ずファイルの中身を確認します。
alembic revision --autogenerate -m "add column fuga"
alembic upgrade head
マイグレーションファイルを修正する必要のあるケースをいくつか紹介します。
NOT NULL制約をつけたカラムを追加する場合
デフォルト値を設定しないと、マイグレーションを実施する際エラーになります。
ERROR: op.add_column("hoge", sa.Column("updated_at", sa.DateTime(), nullable=False))
OK: op.add_column("hoge", sa.Column("updated_at", sa.DateTime(), nullable=False, server_default="2023-08-24 15:26:19.220144"))
カラムをリネームする場合
自動生成されたコードはdrop_column
してからadd_column
するコードになっています。そのまま実行するとデータが消えてしまうので、alter_column
に修正します。
with op.batch_alter_table("hoge", schema=None) as batch_op:
batch_op.alter_column("pub_date", nullable=False, new_column_name="pub_datetime", existing_type=sqlalchemy.DateTime)
SQLiteでカラムをリネームする場合
SQLiteにはalter column
がありません。そこで、render_as_batch=True
を指定するとSQLiteでも実行できるようになります。振る舞いとしては、新しいテーブルに新しいカラムを作成して、データを一方からもう一方にコピーします。
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
render_as_batch=True,
)
なお、バッチモードはSQLite以外のデータベースには影響しません。通常のマイグレーションが実行されます。 https://alembic.sqlalchemy.org/en/latest/batch.html#batch-mode-with-autogenerate
This mode is safe to use in all cases, as the Operations.batch_alter_table() directive by default only takes place for SQLite; other backends will behave just as they normally do in the absence of the batch directives.
私が作業中に飲んでいるコーヒーや欲しいマンガなどを集めました。開発・執筆の励みになりますのでクリックして頂ければ幸いです。
<Amazon欲しいものリスト>