Skip to content

從 Pydantic v1 遷移到 Pydantic v2

🌐 AI 與人類共同完成的翻譯

此翻譯由人類指導的 AI 完成。🤝

可能會有對原意的誤解,或讀起來不自然等問題。🤖

你可以透過協助我們更好地引導 AI LLM來改進此翻譯。

英文版

如果你有一個舊的 FastAPI 應用,可能正在使用 Pydantic 1 版。

FastAPI 0.100.0 同時支援 Pydantic v1 或 v2,會使用你已安裝的那個版本。

FastAPI 0.119.0 透過 Pydantic v2 內的 pydantic.v1 提供對 Pydantic v1 的部分支援,以便遷移到 v2。

FastAPI 0.126.0 移除了對 Pydantic v1 的支援,但在一段時間內仍支援 pydantic.v1

Warning

Pydantic 團隊自 Python 3.14 起,已停止在最新的 Python 版本中支援 Pydantic v1。

這也包含 pydantic.v1,在 Python 3.14 及以上版本不再支援。

如果你想使用最新的 Python 功能,就需要確保使用 Pydantic v2。

如果你的舊 FastAPI 應用仍使用 Pydantic v1,這裡會示範如何遷移到 Pydantic v2,並介紹 FastAPI 0.119.0 中可協助你逐步遷移的功能。

官方指南

Pydantic 提供從 v1 遷移到 v2 的官方遷移指南

其中包含變更內容、驗證如何更正確且更嚴格、可能的注意事項等。

你可以先閱讀以更好理解具體變更。

測試

確保你的應用有測試,並在 CI(持續整合)上執行。

如此一來,你可以升級後確認一切仍如預期運作。

bump-pydantic

在許多情況下,若你使用的是未自訂的標準 Pydantic 模型,多數遷移步驟都能自動化完成。

你可以使用 Pydantic 團隊提供的 bump-pydantic

這個工具會自動修改大部分需要變更的程式碼。

之後執行測試確認一切正常即可完成。😎

v2 中的 Pydantic v1

Pydantic v2 內含子模組 pydantic.v1,提供 Pydantic v1 的所有內容。但在 Python 3.13 以上版本不再支援。

這表示你可以安裝最新的 Pydantic v2,並從該子模組匯入並使用舊的 Pydantic v1 元件,就像安裝了舊版 Pydantic v1 一樣。

from pydantic.v1 import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    size: float

FastAPI 對 v2 中 Pydantic v1 的支援

自 FastAPI 0.119.0 起,也支援透過 Pydantic v2 內的 Pydantic v1(部分)以協助遷移至 v2。

因此,你可以先升級到最新的 Pydantic v2,並將匯入改為使用 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

Warning

請注意,由於 Pydantic 團隊自 Python 3.14 起不再支援 Pydantic v1,因此在 Python 3.14 及以上版本中也不支援使用 pydantic.v1

同一應用同時使用 Pydantic v1 與 v2

Pydantic 不支援在 Pydantic v2 模型的欄位中使用 Pydantic v1 模型,反之亦然。

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 路徑操作(path operation)中同時使用 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

在上面的範例中,輸入模型是 Pydantic v1,輸出模型(於 response_model=ItemV2 定義)是 Pydantic v2。

Pydantic v1 參數

若你需要在 Pydantic v1 模型上使用 FastAPI 的參數工具(例如 BodyQueryForm 等),在完成遷移到 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

分步遷移

Tip

先嘗試使用 bump-pydantic,如果測試通過且一切正常,你就能用一條指令完成遷移。✨

bump-pydantic 不適用於你的情境,可以利用在同一應用同時支援 Pydantic v1 與 v2 的能力,逐步完成遷移。

你可以先升級 Pydantic 到最新 v2,並將所有模型的匯入改為使用 pydantic.v1

接著按群組逐步把模型從 Pydantic v1 遷移到 v2。🚶