committed by
GitHub
19 changed files with 432 additions and 103 deletions
@ -0,0 +1,133 @@ |
|||
# Von Pydantic v1 zu Pydantic v2 migrieren { #migrate-from-pydantic-v1-to-pydantic-v2 } |
|||
|
|||
Wenn Sie eine ältere FastAPI-App haben, nutzen Sie möglicherweise Pydantic Version 1. |
|||
|
|||
FastAPI unterstützt seit Version 0.100.0 sowohl Pydantic v1 als auch v2. |
|||
|
|||
Wenn Sie Pydantic v2 installiert hatten, wurde dieses verwendet. Wenn stattdessen Pydantic v1 installiert war, wurde jenes verwendet. |
|||
|
|||
Pydantic v1 ist jetzt deprecatet und die Unterstützung dafür wird in den nächsten Versionen von FastAPI entfernt, Sie sollten also zu **Pydantic v2 migrieren**. Auf diese Weise erhalten Sie die neuesten Features, Verbesserungen und Fixes. |
|||
|
|||
/// warning | Achtung |
|||
|
|||
Außerdem hat das Pydantic-Team die Unterstützung für Pydantic v1 in den neuesten Python-Versionen eingestellt, beginnend mit **Python 3.14**. |
|||
|
|||
Wenn Sie die neuesten Features von Python nutzen möchten, müssen Sie sicherstellen, dass Sie Pydantic v2 verwenden. |
|||
|
|||
/// |
|||
|
|||
Wenn Sie eine ältere FastAPI-App mit Pydantic v1 haben, zeige ich Ihnen hier, wie Sie sie zu Pydantic v2 migrieren, und die **neuen Features in FastAPI 0.119.0**, die Ihnen bei einer schrittweisen Migration helfen. |
|||
|
|||
## Offizieller Leitfaden { #official-guide } |
|||
|
|||
Pydantic hat einen offiziellen <a href="https://docs.pydantic.dev/latest/migration/" class="external-link" target="_blank">Migrationsleitfaden</a> von v1 zu v2. |
|||
|
|||
Er enthält auch, was sich geändert hat, wie Validierungen nun korrekter und strikter sind, mögliche Stolpersteine, usw. |
|||
|
|||
Sie können ihn lesen, um besser zu verstehen, was sich geändert hat. |
|||
|
|||
## Tests { #tests } |
|||
|
|||
Stellen Sie sicher, dass Sie [Tests](../tutorial/testing.md){.internal-link target=_blank} für Ihre App haben und diese in Continuous Integration (CI) ausführen. |
|||
|
|||
Auf diese Weise können Sie das Update durchführen und sicherstellen, dass weiterhin alles wie erwartet funktioniert. |
|||
|
|||
## `bump-pydantic` { #bump-pydantic } |
|||
|
|||
In vielen Fällen, wenn Sie reguläre Pydantic-Modelle ohne Anpassungen verwenden, können Sie den Großteil des Prozesses der Migration von Pydantic v1 auf Pydantic v2 automatisieren. |
|||
|
|||
Sie können <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> vom selben Pydantic-Team verwenden. |
|||
|
|||
Dieses Tool hilft Ihnen, den Großteil des zu ändernden Codes automatisch anzupassen. |
|||
|
|||
Danach können Sie die Tests ausführen und prüfen, ob alles funktioniert. Falls ja, sind Sie fertig. 😎 |
|||
|
|||
## Pydantic v1 in v2 { #pydantic-v1-in-v2 } |
|||
|
|||
Pydantic v2 enthält alles aus Pydantic v1 als Untermodul `pydantic.v1`. |
|||
|
|||
Das bedeutet, Sie können die neueste Version von Pydantic v2 installieren und die alten Pydantic‑v1‑Komponenten aus diesem Untermodul importieren und verwenden, als hätten Sie das alte Pydantic v1 installiert. |
|||
|
|||
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *} |
|||
|
|||
### FastAPI-Unterstützung für Pydantic v1 in v2 { #fastapi-support-for-pydantic-v1-in-v2 } |
|||
|
|||
Seit FastAPI 0.119.0 gibt es außerdem eine teilweise Unterstützung für Pydantic v1 innerhalb von Pydantic v2, um die Migration auf v2 zu erleichtern. |
|||
|
|||
Sie könnten also Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass das Untermodul `pydantic.v1` verwendet wird, und in vielen Fällen würde es einfach funktionieren. |
|||
|
|||
{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *} |
|||
|
|||
/// warning | Achtung |
|||
|
|||
Beachten Sie, dass, da das Pydantic‑Team Pydantic v1 in neueren Python‑Versionen nicht mehr unterstützt, beginnend mit Python 3.14, auch die Verwendung von `pydantic.v1` unter Python 3.14 und höher nicht unterstützt wird. |
|||
|
|||
/// |
|||
|
|||
### Pydantic v1 und v2 in derselben App { #pydantic-v1-and-v2-on-the-same-app } |
|||
|
|||
Es wird von Pydantic **nicht unterstützt**, dass ein Pydantic‑v2‑Modell Felder hat, die als Pydantic‑v1‑Modelle definiert sind, und umgekehrt. |
|||
|
|||
```mermaid |
|||
graph TB |
|||
subgraph "❌ Nicht unterstützt" |
|||
direction TB |
|||
subgraph V2["Pydantic-v2-Modell"] |
|||
V1Field["Pydantic-v1-Modell"] |
|||
end |
|||
subgraph V1["Pydantic-v1-Modell"] |
|||
V2Field["Pydantic-v2-Modell"] |
|||
end |
|||
end |
|||
|
|||
style V2 fill:#f9fff3 |
|||
style V1 fill:#fff6f0 |
|||
style V1Field fill:#fff6f0 |
|||
style V2Field fill:#f9fff3 |
|||
``` |
|||
|
|||
... aber Sie können getrennte Modelle, die Pydantic v1 bzw. v2 nutzen, in derselben App verwenden. |
|||
|
|||
```mermaid |
|||
graph TB |
|||
subgraph "✅ Unterstützt" |
|||
direction TB |
|||
subgraph V2["Pydantic-v2-Modell"] |
|||
V2Field["Pydantic-v2-Modell"] |
|||
end |
|||
subgraph V1["Pydantic-v1-Modell"] |
|||
V1Field["Pydantic-v1-Modell"] |
|||
end |
|||
end |
|||
|
|||
style V2 fill:#f9fff3 |
|||
style V1 fill:#fff6f0 |
|||
style V1Field fill:#fff6f0 |
|||
style V2Field fill:#f9fff3 |
|||
``` |
|||
|
|||
In einigen Fällen ist es sogar möglich, sowohl Pydantic‑v1‑ als auch Pydantic‑v2‑Modelle in derselben **Pfadoperation** Ihrer FastAPI‑App zu verwenden: |
|||
|
|||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *} |
|||
|
|||
Im obigen Beispiel ist das Eingabemodell ein Pydantic‑v1‑Modell, und das Ausgabemodell (definiert in `response_model=ItemV2`) ist ein Pydantic‑v2‑Modell. |
|||
|
|||
### Pydantic v1 Parameter { #pydantic-v1-parameters } |
|||
|
|||
Wenn Sie einige der FastAPI-spezifischen Tools für Parameter wie `Body`, `Query`, `Form`, usw. zusammen mit Pydantic‑v1‑Modellen verwenden müssen, können Sie die aus `fastapi.temp_pydantic_v1_params` importieren, während Sie die Migration zu Pydantic v2 abschließen: |
|||
|
|||
{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *} |
|||
|
|||
### In Schritten migrieren { #migrate-in-steps } |
|||
|
|||
/// tip | Tipp |
|||
|
|||
Probieren Sie zuerst `bump-pydantic` aus. Wenn Ihre Tests erfolgreich sind und das funktioniert, sind Sie mit einem einzigen Befehl fertig. ✨ |
|||
|
|||
/// |
|||
|
|||
Wenn `bump-pydantic` für Ihren Anwendungsfall nicht funktioniert, können Sie die Unterstützung für Pydantic‑v1‑ und Pydantic‑v2‑Modelle in derselben App nutzen, um die Migration zu Pydantic v2 schrittweise durchzuführen. |
|||
|
|||
Sie könnten zuerst Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass für all Ihre Modelle `pydantic.v1` verwendet wird. |
|||
|
|||
Anschließend können Sie beginnen, Ihre Modelle gruppenweise von Pydantic v1 auf v2 zu migrieren – in kleinen, schrittweisen Etappen. 🚶 |
|||
|
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,123 @@ |
|||
import sys |
|||
from typing import Any, Dict, List, Literal, Sequence, Tuple, Type, Union |
|||
|
|||
from fastapi.types import ModelNameMap |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
|
|||
class AnyUrl: |
|||
pass |
|||
|
|||
class BaseConfig: |
|||
pass |
|||
|
|||
class BaseModel: |
|||
pass |
|||
|
|||
class Color: |
|||
pass |
|||
|
|||
class CoreSchema: |
|||
pass |
|||
|
|||
class ErrorWrapper: |
|||
pass |
|||
|
|||
class FieldInfo: |
|||
pass |
|||
|
|||
class GetJsonSchemaHandler: |
|||
pass |
|||
|
|||
class JsonSchemaValue: |
|||
pass |
|||
|
|||
class ModelField: |
|||
pass |
|||
|
|||
class NameEmail: |
|||
pass |
|||
|
|||
class RequiredParam: |
|||
pass |
|||
|
|||
class SecretBytes: |
|||
pass |
|||
|
|||
class SecretStr: |
|||
pass |
|||
|
|||
class Undefined: |
|||
pass |
|||
|
|||
class UndefinedType: |
|||
pass |
|||
|
|||
class Url: |
|||
pass |
|||
|
|||
from .v2 import ValidationError, create_model |
|||
|
|||
def get_definitions( |
|||
*, |
|||
fields: List[ModelField], |
|||
model_name_map: ModelNameMap, |
|||
separate_input_output_schemas: bool = True, |
|||
) -> Tuple[ |
|||
Dict[ |
|||
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue |
|||
], |
|||
Dict[str, Dict[str, Any]], |
|||
]: |
|||
return {}, {} # pragma: no cover |
|||
|
|||
|
|||
else: |
|||
from .v1 import AnyUrl as AnyUrl |
|||
from .v1 import BaseConfig as BaseConfig |
|||
from .v1 import BaseModel as BaseModel |
|||
from .v1 import Color as Color |
|||
from .v1 import CoreSchema as CoreSchema |
|||
from .v1 import ErrorWrapper as ErrorWrapper |
|||
from .v1 import FieldInfo as FieldInfo |
|||
from .v1 import GetJsonSchemaHandler as GetJsonSchemaHandler |
|||
from .v1 import JsonSchemaValue as JsonSchemaValue |
|||
from .v1 import ModelField as ModelField |
|||
from .v1 import NameEmail as NameEmail |
|||
from .v1 import RequiredParam as RequiredParam |
|||
from .v1 import SecretBytes as SecretBytes |
|||
from .v1 import SecretStr as SecretStr |
|||
from .v1 import Undefined as Undefined |
|||
from .v1 import UndefinedType as UndefinedType |
|||
from .v1 import Url as Url |
|||
from .v1 import ValidationError, create_model |
|||
from .v1 import get_definitions as get_definitions |
|||
|
|||
|
|||
RequestErrorModel: Type[BaseModel] = create_model("Request") |
|||
|
|||
|
|||
def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]: |
|||
use_errors: List[Any] = [] |
|||
for error in errors: |
|||
if isinstance(error, ErrorWrapper): |
|||
new_errors = ValidationError( # type: ignore[call-arg] |
|||
errors=[error], model=RequestErrorModel |
|||
).errors() |
|||
use_errors.extend(new_errors) |
|||
elif isinstance(error, list): |
|||
use_errors.extend(_normalize_errors(error)) |
|||
else: |
|||
use_errors.append(error) |
|||
return use_errors |
|||
|
|||
|
|||
def _regenerate_error_with_loc( |
|||
*, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...] |
|||
) -> List[Dict[str, Any]]: |
|||
updated_loc_errors: List[Any] = [ |
|||
{**err, "loc": loc_prefix + err.get("loc", ())} |
|||
for err in _normalize_errors(errors) |
|||
] |
|||
|
|||
return updated_loc_errors |
|||
Loading…
Reference in new issue