为何Pydantic将Json[Any]|str字段按字符串校验?如何返回字典?
Pydantic Union类型解析差异原因及解决方案
原因分析
Pydantic处理Union类型时,会按类型声明的顺序依次尝试匹配输入值:
- 对于
Json[Any] | str:输入的JSON格式字符串本身就是合法的str类型,无需转换就能匹配成功,因此Pydantic直接将其保留为字符串类型,不会触发后续的JSON解析逻辑。 - 对于
Json[Any] | int:输入的字符串无法转换为int类型(转换失败),Pydantic才会继续尝试下一个类型Json[Any],此时会自动将JSON字符串解析为对应的字典类型。
解决方案
如果需要让Json[Any] | str的场景优先尝试解析JSON字符串为字典,仅当解析失败时才保留字符串,可以通过自定义前置验证器实现:
from typing import Any from json import loads, JSONDecodeError from pydantic import BaseModel, Json, BeforeValidator def try_parse_json(value: Any) -> Any: # 仅对字符串尝试JSON解析 if isinstance(value, str): try: return loads(value) except JSONDecodeError: # 解析失败则返回原字符串 pass return value class FooStr(BaseModel): json_or_str: Json[Any] | str = BeforeValidator(try_parse_json) if __name__ == "__main__": print(type(FooStr(json_or_str='{"a": 1}').json_or_str)) # 输出 <class 'dict'> print(type(FooStr(json_or_str='plain text').json_or_str)) # 输出 <class 'str'>
这个验证器会先尝试将输入的字符串解析为JSON对象,解析失败时再保留原字符串,从而实现预期的优先级逻辑。
内容的提问来源于stack exchange,提问作者Brendan Maguire
相关产品推荐
相关产品推荐

