使用Pydantic解析JSON报错:'NoneType' object is not subscriptable
问题分析与解决方案
核心错误原因
你遇到的'NoneType' object is not subscriptable错误,根源在于**ImportInModel中的两个root_validator函数没有返回处理后的values字典**。Pydantic的根验证器需要返回修改后的(或原封不动的)values对象,否则验证流程会得到None,后续尝试访问None['type']这类操作就会触发类型错误。
另外,ImportsInModel中的check_parent验证逻辑也存在问题,当前的两两循环断言会导致测试数据直接失败,需要调整逻辑。
修正后的代码
1. 修复ImportInModel的根验证器
给每个root_validator添加返回值:
from enum import Enum from pydantic import BaseModel, constr, PositiveInt, root_validator, validator, ValidationError from datetime import datetime import ujson class FileTypeEnum(str, Enum): file = 'FILE' folder = 'FOLDER' class ImportInModel(BaseModel): id: constr(min_length=1) url: constr(max_length=255) | None = None parentId: str | None = None size: PositiveInt | None = None type: FileTypeEnum @root_validator def check_url(cls, values: dict): file_type = values['type'] file_url = values.get('url') if file_type == FileTypeEnum.folder and file_url is not None: raise ValueError( f"{file_type}'s type item should not have a url!" ) # 必须返回values,否则后续处理会拿到None return values @root_validator def check_size(cls, values: dict): file_type = values['type'] file_size = values.get('size') if file_type == FileTypeEnum.file and file_size is None: raise ValueError( f"{file_type}'s type item must have a size!" ) # 必须返回values return values
2. 修复ImportsInModel的父节点验证逻辑
原逻辑会遍历所有item两两对比,只要有一对不满足断言就报错,这不符合实际需求。正确的逻辑应该是:所有文件类型的item,其parentId必须对应列表中存在的文件夹类型item。
class ImportsInModel(BaseModel): items: list[ImportInModel] updateDate: datetime class Config: json_encoders = { datetime: lambda dt: dt.isoformat() } json_loads = ujson.loads @validator('items') def check_parent_valid(cls, v): # 先收集所有文件夹的id folder_ids = {item.id for item in v if item.type == FileTypeEnum.folder} for item in v: if item.type == FileTypeEnum.file: # 文件必须有parentId,且parentId对应存在的文件夹 if item.parentId is None: raise ValueError(f"File {item.id} must have a parentId") if item.parentId not in folder_ids: raise ValueError(f"File {item.id}'s parent {item.parentId} is not a valid folder") return v
3. 测试修正后的代码
测试数据需要补充对应的文件夹item,否则父节点验证会失败:
try: json_raw = '''{ "items": [ { "id": "элемент_1_1", "parentId": null, "size": null, "type": "FOLDER" }, { "id": "элемент_1_4", "url": "/file/url1", "parentId": "элемент_1_1", "size": 234, "type": "FILE" } ], "updateDate": "2022-05-28T21:12:01.000Z" }''' result = ImportsInModel.parse_raw(json_raw) print("验证成功:", result) except ValidationError as e: print(e)
关键注意事项
- 根验证器(
root_validator)必须返回values,否则会导致后续处理拿到None值。 - 验证逻辑要贴合实际业务需求,避免无意义的全量两两对比。
- 使用
values.get(key)代替直接values[key]可以避免部分字段未被验证时的KeyError(防御性写法)。
内容的提问来源于stack exchange,提问作者aalexren
相关产品推荐
相关产品推荐

