我使用 Pydantic v2。现在我想从
loc
或验证错误中删除鉴别器值。请看下面的代码:
from pprint import pprint
from typing import Literal, Union, Annotated, Any
from pydantic import BaseModel, Field, RootModel, ValidationError
from pydantic.main import Model
class Tiger(BaseModel):
animal_type: Literal["tiger"] = "tiger"
ferocity_scale: float = Field(..., ge=0, le=10)
class Shark(BaseModel):
animal_type: Literal["shark"] = "shark"
ferocity_scale: float = Field(..., ge=0, le=10)
class Lion(BaseModel):
animal_type: Literal["lion"] = "lion"
ferocity_scale: float
class WildAnimal(RootModel):
root: Annotated[Union[Tiger, Shark, Lion], Field(..., discriminator='animal_type')]
try:
my_shark = WildAnimal.model_validate({'animal_type': 'shark', 'ferocity_scale': 115})
except ValidationError as exc:
pprint(exc.errors())
代码打印:
[{'ctx': {'le': 10.0},
'input': 115,
'loc': ('shark', 'ferocity_scale'), <------ how to drop "shark"?
'msg': 'Input should be less than or equal to 10',
'type': 'less_than_equal',
'url': 'https://errors.pydantic.dev/2.7/v/less_than_equal'}]
在
loc
键中,您可以注意到 ('shark', 'ferocity_scale')
。值 shark
是鉴别器 animal_type
值。
如何通过Pydantic删除它?或者如何动态检测
loc
的第一个值是鉴别器值?
我唯一能弄清楚的是:
class WildAnimal(RootModel):
root: Annotated[Union[Tiger, Shark, Lion], Field(..., discriminator='animal_type')]
@classmethod
def model_validate(cls: type[Model], obj: Any, *, strict: bool | None = None, from_attributes: bool | None = None,
context: dict[str, Any] | None = None) -> Model:
try:
return super().model_validate(obj, strict=strict, from_attributes=from_attributes, context=context)
except ValidationError as exc:
# modify loc
# reraise ValidationError
必须实现装饰器:
def reconstruct_validation_error(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except ValidationError as e:
errors = e.errors()
for error in errors:
error["loc"] = tuple(list(error["loc"])[1:])
title, _ = func.__qualname__.split(".", maxsplit=1)
raise ValidationError.from_exception_data(title=title, line_errors=errors)
return wrapper
class WildAnimal(RootModel):
root: Annotated[
Union[Tiger, Shark, Lion],
Field(..., discriminator='animal_type'),
]
@reconstruct_validation_error
def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None:
super().__init__(root, **data)