mapped_column と Column の違い
SQLAlchemyのORMを使う際、テーブルカラムを定義する方法としてmapped_column()
とColumn()
の2つの方法が存在します。この違いを理解することは、効果的なORMモデル設計に不可欠です。
問題の本質
- 従来の
Column()
はSQLAlchemyのコアレイヤー(SQL式言語) とORMレイヤーの両方で使用されていた - この設計により責務が分散し、ORM特有の機能拡張が困難になっていた
- 混在が原因で型ヒントとの統合や静的解析が制限される問題があった
推奨ソリューション:mapped_column
の採用
SQLAlchemy 2.0以降のベストプラクティス
ORMモデルを定義する場合はmapped_column()
の使用が公式推奨されています
推奨: mapped_columnを使用
class User(DeclarativeBase): tablename = "users"
id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column() age: Mapped[int | None] # mapped_column省略形
# 非推奨: 従来のColumn使用 class LegacyUser(Base): __tablename__ = "legacy_users" id = Column(Integer, primary_key=True) name = Column(String) age = Column(Integer, nullable=True)
主要な機能比較
特徴 | Column | mapped_column |
---|---|---|
レイヤーの対応 | コア & ORM | ORM専用 |
型ヒント連携 | 不可 | 可能 |
nullable の自動設定 | 手動 | Optional で自動 |
カラムタイプ推論 | 不可 | Python型から推論 |
mypy連携 | 一部 | 完全対応 |
実用的メリット解説
1. 型ヒントによる自動推論
python
class Product(DeclarativeBase):
# VARCHARとnullable=Falseを自動設定
name: Mapped[str]
# BIGINTを推論
stock: Mapped[int]
# BOOLEAN & nullable=True を自動設定
is_active: Mapped[bool | None]
2. ボイラープレート削減
python
# 従来 (18文字)
active = Column(Boolean, nullable=False)
# 新しい方法 (9文字)
active: Mapped[bool]
3. 型安全性の向上
python
product = session.get(Product, 1)
# Mappedで定義した場合
print(product.stock + 10) # 正しい操作
# 定義していない属性は検出可能
print(product.undefined_attr) # mypyエラー発生
利用上の注意点
混在使用パターン
WARNING
Column
とmapped_column
は同じモデル内で併用可能ですが非推奨です。移行中の一時的措置として扱ってください
py
class TransitionModel(DeclarativeBase):
id: Mapped[int] = mapped_column(primary_key=True)
# 移行中のレガシー定義
created_at = Column(DateTime)
Column
を今でも使うケース
- SQL式言語(コア機能)のみを使う場合
- レガシーコードをメンテせずに置換対象外とする場合
- 動的カラム生成など高度なメタプログラミングが必要な場合
生成SQLの比較
双方の定義から生成されるSQLテーブルに実質的な違いはありません。機能差はORM層限定です。
/* mapped_columnで生成 */ CREATE TABLE users ( id SERIAL NOT NULL, name VARCHAR NOT NULL, age INTEGER, PRIMARY KEY (id) );
/* Columnで生成 ※同じ出力 */ CREATE TABLE legacy_users ( id SERIAL NOT NULL, name VARCHAR NOT NULL, age INTEGER, PRIMARY KEY (id) );
移行ガイド
DeclarativeBase
の新規モデルではmapped_column
を一貫使用- 既存プロジェクト:diff
- from sqlalchemy import Column + from sqlalchemy.orm import Mapped, mapped_column
- 型ヒント対応:diff
- name = Column(String) + name: Mapped[str] = mapped_column()
nullable
設定の簡略化:diff- active = Column(Boolean, nullable=True) + active: Mapped[bool | None]
::: success ベネフィットまとめ
- 開発効率:型ヒント自動設定でコード量50%削減
- 保守性:静的型チェックが可能に
- 未来安全性:新機能は
mapped_column
に優先実装 - 学習コスト:Pythonネイティブ型で統一可能 :::