Миграция с Pydantic v1 на Pydantic v2¶
Если у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.
FastAPI поддерживает и Pydantic v1, и v2 начиная с версии 0.100.0.
Если у вас был установлен Pydantic v2, использовался он. Если вместо этого был установлен Pydantic v1 — использовался он.
Сейчас Pydantic v1 объявлен устаревшим, и поддержка его будет удалена в следующих версиях FastAPI, поэтому вам следует перейти на Pydantic v2. Так вы получите последние возможности, улучшения и исправления.
Предупреждение
Кроме того, команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с 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.
Это означает, что вы можете установить последнюю версию 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
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. Если тесты проходят и всё работает, вы справились одной командой. ✨
Если bump-pydantic не подходит для вашего случая, вы можете использовать поддержку одновременной работы моделей Pydantic v1 и v2 в одном приложении, чтобы мигрировать на Pydantic v2 постепенно.
Сначала обновите Pydantic до последней 2-й версии и измените импорты так, чтобы все ваши модели использовали pydantic.v1.
Затем начните мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶