
本文介绍如何使用 Pydantic 内置的 jsonValue 类型(v2.0+)安全、高效地校验任意层级嵌套的 json 兼容数据(如字典、列表、字符串、数字、布尔值或 None),避免递归类型定义错误,并确保值可无损序列化为标准 JSON。
本文介绍如何使用 pydantic 内置的 `jsonvalue` 类型(v2.0+)安全、高效地校验任意层级嵌套的 json 兼容数据(如字典、列表、字符串、数字、布尔值或 none),避免递归类型定义错误,并确保值可无损序列化为标准 json。
在构建 API 或处理外部输入时,我们常需确保某个字段是「真正可 JSON 序列化的数据」——即它必须能被 json.dumps() 无异常地转换为 JSON 字符串。虽然 Dict[str, Any] 看似可用,但它允许 datetime、UUID、自定义对象等非 JSON 原生类型,导致后续序列化失败;而 pydantic.Json 仅用于解析 JSON 字符串(如 ‘”hello”‘ → “hello”),不适用于已解析的 Python 数据结构。
Pydantic v2 起提供了开箱即用的 JsonValue 类型,专为此场景设计。它是一个严格受限的联合类型,精确对应 JSON 规范支持的 7 种原子与复合值:
from pydantic import BaseModel, JsonValue from typing import Dict, List # ✅ 正确:直接校验任意 JSON 兼容值 class PayloadModel(BaseModel): data: JsonValue # ✅ 正确:若明确要求顶层为对象(即 JSON object),可限定为字典 class ObjectModel(BaseModel): config: Dict[str, JsonValue] # ✅ 示例:合法输入(全部可通过校验) valid_inputs = [ {"name": "Alice", "scores": [95, 87], "active": True, "meta": None}, ["a", 42, False], "string", 3.14, None, ] for inp in valid_inputs: try: model = PayloadModel(data=inp) print(f"✓ Valid: {inp}") except Exception as e: print(f"✗ Invalid: {inp} → {e}") # ❌ 以下会校验失败(因不可 JSON 序列化) invalid_inputs = [ {"created_at": datetime.now()}, # datetime 不在 JsonValue 中 {"id": uuid4()}, # UUID 不被允许 {"func": lambda x: x}, # 可调用对象非法 ]
⚠️ 注意事项:
- JsonValue 不包含 bytes、decimal.Decimal、enum、datetime 等常见非 JSON 类型,这是其核心设计目标:保证 .model_dump_json() 或 json.dumps(model.model_dump()) 永远不会抛出 TypeError。
- 若需支持扩展类型(如 datetime 转 ISO 字符串),应配合 @field_serializer 自定义序列化逻辑,而非放宽 JsonValue 类型。
- 在 Pydantic v1 中无原生等价物,需手动定义递归类型(易出错且不推荐);升级至 v2+ 是最佳实践。
- JsonValue 是 type alias,非运行时校验器,但其类型提示会与 Pydantic 的验证逻辑深度协同,提供静态检查 + 动态校验双重保障。
总结而言,JsonValue 是校验「已解析 JSON 数据结构」的黄金标准。当你的模型字段预期接收来自 json.loads() 的结果、前端传来的原始对象/数组,或需确保下游 json.dumps() 安全时,请直接使用 JsonValue —— 简洁、准确、零配置,且完全符合 JSON 规范语义。