Миграция с Pydantic v1 на Pydantic v2¶
Если у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.
FastAPI версии 0.100.0 поддерживал либо Pydantic v1, либо v2. Он использовал ту версию, которая была установлена.
FastAPI версии 0.119.0 добавил частичную поддержку Pydantic v1 изнутри Pydantic v2 (как pydantic.v1), чтобы упростить миграцию на v2.
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать pydantic.v1.
Предупреждение
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с Python 3.14.
Это включает 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 v1 на Pydantic v2.
Вы можете использовать bump-pydantic от той же команды 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
🤓 Other versions and variants
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 v1 изнутри Pydantic v2, чтобы упростить миграцию на 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
🤓 Other versions and variants
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, использование pydantic.v1 также не поддерживается в Python 3.14 и выше.
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
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же операции пути (обработчике пути) вашего приложения FastAPI:
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
🤓 Other versions and variants
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, вы можете импортировать их из fastapi.temp_pydantic_v1_params, пока завершаете миграцию на Pydantic v2:
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
🤓 Other versions and variants
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 группами, поэтапно. 🚶