1
1

alembicで作成されるカラムの順序を指定するmapped_columnとsort_orderの使い方

Posted at

よくある実装と発生する問題

SQLAlchemyとalembicを使用している場合、モデルのベースを作り、下記のように継承させる方法をよくとると思います。

base.py
from sqlalchemy import Column, DATETIME, Integer, func

class ModelBase:
    id = Column(Integer, primary_key=True)
    created_at = Column(DATETIME, nullable=False, server_default=func.now())
    updated_at = Column(
        DATETIME,
        nullable=False,
        server_default=func.now(),
        onupdate=func.now(),
    )

user.py
from sqlalchemy import Column, String
from app.db.base_class import Base
from app.models.base import ModelBase

class User(Base, ModelBase):
    __tablename__ = "users"
    name = Column(String(255), nullable=False)

しかし、上記の実装では、
name, id, created_at, updated_atの順に作成されてしまいます。
使えなくはないですが、なんだかしっくりこないですね。
table.png

実際に、migrationファイルも下記のように書かれています。

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('users',
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('created_at', sa.DATETIME(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_at', sa.DATETIME(), server_default=sa.text('now()'), nullable=False),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

対処法

下記のように、mapped_columnsort_orderを使用することで、順番を正しいものにすることができます。

base.py
from sqlalchemy import DATETIME, Integer, func
from sqlalchemy.orm import mapped_column


class ModelBase:
    id = mapped_column(Integer, primary_key=True, sort_order=-10)
    created_at = mapped_column(
        DATETIME, nullable=False, server_default=func.now(), sort_order=98
    )
    updated_at = mapped_column(
        DATETIME,
        nullable=False,
        server_default=func.now(),
        onupdate=func.now(),
        sort_order=99,
    )

結果

table2.png

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1