SQLAlchemyでテーブル定義を記述するときに, いくつかのテーブルで定義するカラムは既定クラスやMixinクラスに書くことがあります.
SQLAlchemy 1.4以前だと, そのときに出力されるDDLのカラムの順序がコントロールしづらいと思っていましたが, SQLAlchemy 2.0でそのあたりが改善していたことに気づいたのでかんたんに紹介します.
SQLAlchemy 1.4 の場合
SQLAlchemy 1.4 で既定エンティティクラス Base でPKを記述し, メタデータ相当のカラム created_at をMixinクラスで定義すると, こんな感じの書き方になると思います.
class _Base(object):
id = Column(Integer, primary_key=True, autoincrement=True)
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
Base = declarative_base(cls=_Base)
class TimestampMixin(object):
created_at = Column(DateTime, nullable=False)
class Item(TimestampMixin, Base):
name = Column(String, nullable=False)
この class Item から次のようなDDLを生成できます.
CREATE TABLE item (
id INTEGER NOT NULL,
created_at DATETIME NOT NULL,
name VARCHAR NOT NULL,
PRIMARY KEY (id)
)
気持ち的にはちょっと違う感じしますね. created_at を一番下に持ってきてほしい.
SQLAlchemyと一緒に使われるマイグレーションツール Alembic でも, 同じようなスクリプトが出力されます.
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('item',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
Alembicのスクリプトのなかに「please adjust!」とあるように, 適宜入れ替えればいいだけですし, Base.metadata.create_all(engine)
をプロダクションコードで使うことも少ない気がしますが…….
SQLAlchemy 2.0 ではそのあたりがコントロールできるようになっていました.
SQLAlchemy 2.0 ではsort_orderでカラムの順序を指定できる
SQLAlchemy2.0でカラム定義に使う mapped_column の sort_order 引数でカラムの順序をコントロールできるようになりました.
class Base(DeclarativeBase):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, sort_order=-10)
@declared_attr.directive
def __tablename__(cls) -> str:
return cls.__name__.lower()
class TimestampMixin(object):
created_at: Mapped[datetime.datetime] = mapped_column(sort_order=10)
class Item(TimestampMixin, Base):
name: Mapped[str]
次のDDLが出力されます. 期待したとおりですね.
CREATE TABLE item (
id INTEGER NOT NULL,
name VARCHAR NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (id)
)
sort_order はデフォルト 0 なので, 負数をしておけば上に, 正数をしておけば下にカラムが出力されます.
SQLAlchemy 2.0 で利用できるようになった機能のなかでは目立たないものかなと思いますが, 雑にコードを書き捨てたい僕にはちょっとうれしいものでした. ちなみに使えるのは2.0.4 からみたいです.
参考