はじめに
本記事はalembicとSQLAlchemyを使用してマイグレーションを管理しているプロジェクトで新規テーブルを追加した際に発生したことをまとめた備忘録です。
環境
Python 3.11.5
alembic 1.13.0
SQLAlchemy 2.0.23
mysql 8.0.34
何があったの?
とある目的で別テーブルで管理しているIDをPKにしたテーブルを作成することになりました。
他テーブルのPKをそのままPKとして使用するためautoincrementはFalseにする必要がありました。
ユーザー登録をする際はまずusersにレコードが生成されて、その生成されたレコードのPKをそのままuser_detailsのPKにする想定。
以下は実際に発生した事象を再現したものになります。
class User(Base):
__tablename__ = 'users'
id = Column(BIGINT, primary_key=True, autoincrement=True)
last_name = Column(VARCHAR(16))
first_name = Column(VARCHAR(16))
以下、マイグレーションにより実際に作成されたusersテーブル
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| last_name | varchar(16) | YES | | NULL | |
| first_name | varchar(16) | YES | | NULL | |
+------------+-------------+------+-----+---------+----------------+
class UserDetail(Base):
__tablename__ = 'user_details'
user_id = Column(BIGINT, primary_key=True)
height = Column(INTEGER)
weight = Column(INTEGER)
以下、マイグレーションにより追加されたuser_detailsテーブル
+---------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+----------------+
| user_id | bigint | NO | PRI | NULL | auto_increment |
| height | int | YES | | NULL | |
| weight | int | YES | | NULL | |
+---------+--------+------+-----+---------+----------------+
ここであれっ?てなりました。
user_detailsの定義にはPKであるuser_idのautoincrementは何も指定していないのに勝手にautoincrementされる設定になってる...
対応
まずは公式ドキュメントを確認。
https://docs.sqlalchemy.org/en/20/core/metadata.html#sqlalchemy.schema.Column.params.autoincrement
以下、該当部分の引用
The default value is the string "auto", which indicates that a single-column (i.e. non-composite) primary key that is of an INTEGER type with no other client-side or server-side default constructs indicated should receive auto increment semantics automatically. Other values include True (force this column to have auto-increment semantics for a composite primary key as well), False (this column should never have auto-increment semantics), and the string "ignore_fk" (special-case for foreign key columns, see below).
autoincrementのデフォルト値ってFalseじゃないんだ!!
autoincrementのデフォルトは'auto'でINT型(もっと言うとINT, SMALLINT, BIGINT)でかつ、複合主キーでなければ自動的にオートインクリメントされる設定になるみたいでした。
なので明示的にautoincrementをFalseにするとauto_incrementが外れました。
class UserDetail(Base):
__tablename__ = 'user_details'
user_id = Column(BIGINT, primary_key=True, autoincrement=False)
height = Column(INTEGER)
weight = Column(INTEGER)
以下、マイグレーションにより追加された修正版のuser_detailsテーブル
+---------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+-------+
| user_id | bigint | NO | PRI | NULL | |
| height | int | YES | | NULL | |
| weight | int | YES | | NULL | |
+---------+--------+------+-----+---------+-------+
めでたしめでたし。
参考文献
- SQLAlchemy 2.0 Documentation
https://docs.sqlalchemy.org/en/20/index.html