Pydantic 中正确建模 JSON 兼容字典类型的方法

5次阅读

Pydantic 中正确建模 JSON 兼容字典类型的方法

本文详解如何在 Pydantic 中精准定义和验证符合 jsON 序列化规范的嵌套字典结构(即 Dict[str, jsonValue]),避免递归类型错误,确保字段值仅包含 JSON 原生可序列化类型(str/int/Float/bool/None/List/Dict)。

本文详解如何在 pydantic 中精准定义和验证符合 json 序列化规范的嵌套字典结构(即 `dict[str, jsonvalue]`),避免递归类型错误,确保字段值仅包含 json 原生可序列化类型(str/int/float/bool/none/list/dict)。

在构建 API 请求体、配置解析或数据清洗场景中,我们常需严格约束某个字段为「合法的 JSON 值」——它必须能被 json.dumps() 无异常地序列化,即仅允许 JSON 原生支持的类型:字符串、数字(int/float)、布尔值、NULL(对应 Python 的 None)、列表(元素也需 JSON 兼容)和字典(键必须为 str,值也需 JSON 兼容)。此时,简单使用 Dict[str, Any] 过于宽泛(如允许 datetime、set、自定义类等非 JSON 类型),而 pydantic.Json 又仅用于校验 JSON 字符串 的解析结果,均不满足需求。

Pydantic v2+ 提供了开箱即用的类型别名 JsonValue,专为此类场景设计。它是一个前向引用的递归联合类型,定义如下:

from pydantic.types import JsonValue  # ✅ 推荐导入方式(Pydantic >= 2.6) # 或从旧路径(兼容早期 v2.x): # from pydantic import JsonValue  # 等价于(无需手动定义,避免 RecursionError): # JsonValue = union[ #     List["JsonValue"], #     Dict[str, "JsonValue"], #     str, #     bool, #     int, #     float, #     None, # ]

若目标是校验一个JSON 对象(即字典),应直接使用 Dict[str, JsonValue] —— 它确保键为字符串,且所有值(包括嵌套的任意层级)均为 JSON 可序列化类型:

from typing import Dict, List from pydantic import BaseModel, ValidationError from pydantic.types import JsonValue  class ConfigModel(BaseModel):     metadata: Dict[str, JsonValue]  # ✅ 正确:JSON 兼容的字典     tags: List[JsonValue]            # ✅ 同样适用于列表  # ✅ 合法输入(全部可被 json.dumps() 处理) valid_data = {     "metadata": {         "name": "app",         "version": 1.2,         "active": True,         "features": ["auth", "logging"],         "settings": {"timeout": 30, "retry": None}     },     "tags": ["prod", 42, False, None] }  model = ConfigModel(**valid_data)  # ❌ 触发 ValidationError:datetime 不在 JsonValue 范围内 invalid_data = {"metadata": {"created_at": datetime.now()}} try:     ConfigModel(**invalid_data) except ValidationError as e:     print(e) # > 1 validation error for ConfigModel # > metadata -> created_at # >   Input should be a valid string, number, boolean, None, list or dict [type=union_tag_invalid, input_value=datetime.datetime(...), input_type=datetime]

⚠️ 关键注意事项

  • JsonValue 是 运行时类型提示,Pydantic 在实例化时执行深度验证(包括嵌套结构),而非仅做静态类型检查;
  • 不要尝试手动重新定义 JsonValue(如 Union[Dict[str, ‘JsonValue’], …]),会导致 RecursionError —— Pydantic 已通过内部机制安全处理前向引用;
  • 若需接收 JSON 字符串并自动解析为 JsonValue 结构,应使用 Json[JsonValue](注意:Json[T] 表示“传入字符串,解析后验证为 T”);
  • JsonValue 不校验键名是否为合法 JSON 字符串(如含控制字符),但实际 JSON 序列化器(如 json.dumps)会拒绝此类键;Pydantic 默认接受,如需额外约束,可配合 Field(pattern=r’^[^x00-x08x0bx0cx0e-x1f]*$’) 等定制校验。

综上,Dict[str, JsonValue] 是表达「JSON 对象字典」语义最准确、最简洁且经官方验证的方案,兼顾类型安全性与运行时鲁棒性,是 Pydantic v2+ 中处理 JSON 数据结构的标准实践。

text=ZqhQzanResources