Pydantic v1からPydantic v2への移行¶
古いFastAPIアプリをお使いの場合、Pydanticバージョン1を使用している可能性があります。
FastAPIは、バージョン0.100.0以降、Pydantic v1またはv2のいずれかをサポートしています。
Pydantic v2をインストールした場合、それを使用します。代わりにPydantic v1をインストールしていた場合は、そちらを使用します。
Pydantic v1は現在非推奨となっており、FastAPIの次のバージョンでサポートが削除される予定ですので、Pydantic v2に移行してください。これにより、最新の機能、改善、修正を得ることができます。
Warning
また、Pydanticチームは、Python 3.14以降の最新バージョンのPythonに対するPydantic v1のサポートを終了しました。
Pythonの最新機能を使用したい場合は、Pydantic v2を使用するようにしてください。
Pydantic v1を使用している古いFastAPIアプリをお持ちの場合、ここではPydantic v2への移行方法と、段階的な移行を支援するためのFastAPI 0.119.0の新機能について説明します。
公式ガイド¶
Pydanticには、v1からv2への公式の移行ガイドがあります。
変更点、バリデーションがどのように改善され、より正確で厳密になったか、注意点なども含まれています。
変更点をよりよく理解するために、お読みください。
テスト¶
アプリにテストがあることを確認し、継続的インテグレーション(CI)で実行してください。
これにより、アップグレードを行い、すべてが期待どおりに機能していることを確認できます。
bump-pydantic¶
多くの場合、カスタマイズなしで通常のPydanticモデルを使用している場合、Pydantic v1からPydantic v2への移行プロセスを自動化できます。
同じPydanticチームのbump-pydanticを使用できます。
このツールは、変更が必要なコードの大部分を自動的に変更するのに役立ちます。
その後、テストを実行してすべてが機能するかどうかを確認できます。問題がなければ完了です。😎
Pydantic v1をv2で使う¶
Pydantic v2には、Pydantic v1のすべてがサブモジュールpydantic.v1として含まれています。
これは、Pydantic v2の最新バージョンをインストールし、古いPydantic v1コンポーネントをこのサブモジュールからインポートして使用できることを意味します。まるで古いPydantic v1がインストールされているかのように。
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
size: float
🤓 その他のバージョンとバリアント
from typing import Union
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
size: float
FastAPIにおけるPydantic v1とv2のサポート¶
FastAPI 0.119.0以降、Pydantic v2内からのPydantic v1の部分的サポートも提供されており、v2への移行を容易にしています。
そのため、Pydanticを最新のバージョン2にアップグレードし、インポートをpydantic.v1サブモジュールを使用するように変更すると、多くの場合、そのまま動作します。
from fastapi import FastAPI
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
size: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
🤓 その他のバージョンとバリアント
from typing import Union
from fastapi import FastAPI
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
size: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
Warning
Pydanticチームは、Python 3.14以降の最新バージョンではPydantic v1のサポートを終了しているため、pydantic.v1の使用もPython 3.14以降ではサポートされないことに注意してください。
同じアプリでPydantic v1とv2を併用する¶
Pydantic v2のモデルで、そのフィールドがPydantic v1モデルとして定義されている場合、またはその逆の場合、Pydanticではサポートされていません。
graph TB
subgraph "❌ Not Supported"
direction TB
subgraph V2["Pydantic v2 Model"]
V1Field["Pydantic v1 Model"]
end
subgraph V1["Pydantic v1 Model"]
V2Field["Pydantic v2 Model"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
しかし、同じアプリでPydantic v1とv2のモデルを分離して使用することは可能です。
graph TB
subgraph "✅ Supported"
direction TB
subgraph V2["Pydantic v2 Model"]
V2Field["Pydantic v2 Model"]
end
subgraph V1["Pydantic v1 Model"]
V1Field["Pydantic v1 Model"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
場合によっては、FastAPIアプリの同じパス操作でPydantic v1とv2の両方のモデルを使用することも可能です。
from fastapi import FastAPI
from pydantic import BaseModel as BaseModelV2
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
size: float
class ItemV2(BaseModelV2):
name: str
description: str | None = None
size: float
app = FastAPI()
@app.post("/items/", response_model=ItemV2)
async def create_item(item: Item):
return item
🤓 その他のバージョンとバリアント
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel as BaseModelV2
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
size: float
class ItemV2(BaseModelV2):
name: str
description: Union[str, None] = None
size: float
app = FastAPI()
@app.post("/items/", response_model=ItemV2)
async def create_item(item: Item):
return item
上記の例では、入力モデルはPydantic v1モデルであり、出力モデル(response_model=ItemV2で定義)はPydantic v2モデルです。
Pydantic v1のパラメータ¶
Pydantic v1モデルでBody、Query、FormなどのFastAPI固有のパラメータツールを使用する必要がある場合は、Pydantic v2への移行が完了するまでfastapi.temp_pydantic_v1_paramsからインポートできます。
from typing import Annotated
from fastapi import FastAPI
from fastapi.temp_pydantic_v1_params import Body
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
size: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item:
return item
🤓 その他のバージョンとバリアント
from typing import Annotated, Union
from fastapi import FastAPI
from fastapi.temp_pydantic_v1_params import Body
from pydantic.v1 import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
size: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item:
return item
from typing import Union
from fastapi import FastAPI
from fastapi.temp_pydantic_v1_params import Body
from pydantic.v1 import BaseModel
from typing_extensions import Annotated
class Item(BaseModel):
name: str
description: Union[str, None] = None
size: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item:
return item
段階的に移行する¶
ヒント
まずbump-pydanticを試してください。テストがパスして動作すれば、1コマンドで完了です。✨
bump-pydanticがユースケースに合わない場合は、同じアプリでPydantic v1とv2のモデルをサポートすることで、Pydantic v2への移行を段階的に行うことができます。
まずPydanticを最新のバージョン2にアップグレードし、すべてのモデルのインポートをpydantic.v1を使用するように変更できます。
その後、Pydantic v1からv2へのモデルの移行をグループ化して、段階的に開始できます。🚶