如何对对象动态验证自定义Pydantic模型?



我有一个这样的函数:

class Name(BaseModel):
name_id: str
first_name: str 
last_name: str 

def get_all_names() -> List[Name]:
names = []
try:
# this API returns a list of NAME objects
names = requests.get("some-url")
# I want to validate, that each NAME object comforms to the model "Name" above
# this is what I do currently
validate_name_objects = [Name(**each_name_object) for each_name_object in names]
except Exception as e:
# if any of the NAME object fails the validation check above, then it will automatically
# be caught in this exception block and logged
logger.info(f"log this error (could be requests error, could be validation error: {e}")

return names

FastAPI自动执行此验证检查,它以某种方式从函数签名中获取响应的类型提示,在这种情况下将是List[Name],然后如果响应不符合则自动引发异常。

我在代码的很多地方用不同的自定义Pydantic模型进行这种检查。

所以我正在寻找这样的机制:

# Here SOME_FUNCTION takes in 2 arguments: A custom model to compare(which could be in any custom form 
# made from Pydantic models like List[some-model] or Dict[str, some-model], etc) 
# and a payload to validate that model against
validate_name_objects = SOME_FUNCTION(List[Name], names)

如何实现这一点?


我发现与我的问题最接近的内容是Pydantic在这里提供的- https://pydantic-docs.helpmanual.io/usage/validation_decorator/,但这仅用于验证给定函数的输入参数,不接受动态自定义模型。


更新:@MatsLindh回答后,这里有更灵活的方法,我们可以使用他给出的解决方案:(但请记住,正如所指出的,Pydantic是一个解析库->不是一个验证库)

我们只能将它用于本地python数据类型

from typing import Dict
from pydantic import parse_obj_as
items = parse_obj_as(Dict[int, str], {"asdasd": "23232"})
print(items)

这将像预期的那样给出验证错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pydantic/tools.py", line 35, in pydantic.tools.parse_obj_as
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for ParsingModel[Dict]
__root__ -> __key__
value is not a valid integer (type=type_error.integer)

对于自定义数据模型,也可以使用相同的函数:

from typing import List, Dict
from pydantic import BaseModel, parse_obj_as
class Item(BaseModel):
id: int
name: str
items = parse_obj_as(Dict[int, Item], {1: "asdfasdasf"})
print(items)

这将像预期的那样给出验证错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pydantic/tools.py", line 35, in pydantic.tools.parse_obj_as
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for ParsingModel[Dict]
__root__ -> 1
value is not a valid dict (type=type_error.dict)

或者让我们试试更复杂的自定义类型


from typing import List, Dict, Tuple, Optional
from pydantic import BaseModel, parse_obj_as
class Item(BaseModel):
id: int
name: str

items = parse_obj_as(Dict[Tuple[str, Optional[float], Optional[float]], Item], {(1, "123fdsfds", None): {'id': 1, 'name': 'My Item'}})
print(items)

这也给出了一个验证错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pydantic/tools.py", line 35, in pydantic.tools.parse_obj_as
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for ParsingModel[Dict]
__root__ -> __key__ -> 1
value is not a valid float (type=type_error.float)

您可以使用parse_obj_as将字典列表转换为给定Pydantic模型列表,有效地执行与FastAPI返回响应时相同的操作。

from pydantic import parse_obj_as
...
name_objects = parse_obj_as(List[Name], names)

然而,重要的是要考虑Pydantic是一个解析器库,而不是一个验证库——所以如果你的模型允许的话,它会进行转换。