跳到内容

从 Pydantic v1 迁移到 Pydantic v2

如果您有一个旧的 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

警告

Pydantic 团队停止了对最新 Python 版本(从 **Python 3.14** 开始)的 Pydantic v1 的支持。

这包括 pydantic.v1,它在 Python 3.14 及更高版本中不再受支持。

如果您想使用最新的 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。但这在 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
🤓 其他版本和变体
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

警告

请注意,由于 Pydantic 团队不再支持 Pydantic v1 在最近的 Python 版本中(从 Python 3.14 开始),因此在 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 应用的同一个 **路径操作** 中同时拥有 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 参数

如果您需要将一些 FastAPI 特定的参数工具(如 BodyQueryForm 等)与 Pydantic v1 模型一起使用,您可以在完成向 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

分步迁移

提示

首先尝试使用 bump-pydantic,如果您的测试通过并且工作正常,那么您只需一个命令即可完成。✨

如果 bump-pydantic 不适用于您的用例,您可以使用同一个应用中同时支持 Pydantic v1 和 v2 模型的功能来逐步完成迁移到 Pydantic v2。

您可以首先将 Pydantic 升级到最新的 2 版本,并将所有模型的导入更改为使用 pydantic.v1

然后,您可以开始分批、分阶段地将您的模型从 Pydantic v1 迁移到 v2。🚶