从 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 特定的参数工具(如 Body、Query、Form 等)与 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。🚶