Pydantic模型中List[Dict]被解析为单个Dict的问题求助
问题:Pydantic模型中Union[str, Dict, List]无法正确解析List[Dict]类型的msg字段
给定以下Pydantic模型:
from typing import Dict, List, Optional, Union from pydantic import BaseModel class WSMessage(BaseModel): action: str success: Optional[bool] = None sent_from: Optional[str] = None send_to: Optional[str] = None data: Optional[Union[str, Dict, List]] = None msg: Optional[Union[str, Dict, List]] = None reason: Optional[Union[str, Dict, List]] = None class Config: extra = "allow"
以及测试数据:
data = { 'action': 'reply', 'sent_from': 'master', 'send_to': '192.168.0.100_UE4yWw69iSBEf67JhhWTpg==', 'data': None, 'success': True, 'msg': [ {'name': 'entry1_name', 'value': 'entry1_value'}, {'name': 'entry2_name', 'value': 'entry2_value'} ], 'reason': None, 'to_action': 'get_system_properties', 'completed': True, }
将数据加载到模型后,msg字段被错误解析为单个Dict:
>>> msg = WSMessage(**data) >>> msg.msg {'name': 'value'}
移除模型中的msg字段后,数据能正确保留为List[Dict]类型。需要让msg字段支持字符串、字典或列表类型,请问问题出在哪里?
原因分析
问题出在Union类型的匹配顺序以及泛型List的定义方式:
- Pydantic解析Union类型时,会按从左到右的顺序尝试匹配,优先匹配排在前面的类型。
- 原定义中
Dict排在List前面,Pydantic会先尝试将输入的列表解析为Dict。由于列表元素是包含name和value键的字典,Pydantic错误地将这些键值对合并成了一个新Dict(最后一个元素的键覆盖了前面的),最终得到{'name': 'value'}。 - 直接使用无泛型参数的
List,会让Pydantic对列表类型的匹配优先级低于Dict。
解决方案
方案1:调整Union中类型的顺序,将List放在Dict前面
把List移到Dict之前,让Pydantic优先匹配列表类型:
msg: Optional[Union[str, List, Dict]] = None
方案2:使用更具体的泛型类型定义List
明确指定List的元素类型,让Pydantic更准确识别列表类型:
from typing import Any # 支持任意元素的列表 msg: Optional[Union[str, Dict, List[Any]]] = None
如果确定列表元素都是字典,可以进一步明确:
# 仅支持字典元素的列表 msg: Optional[Union[str, Dict, List[Dict]]] = None
验证效果
修改后的模型加载数据后,msg会正确保留为List[Dict]:
>>> msg = WSMessage(**data) >>> msg.msg [{'name': 'entry1_name', 'value': 'entry1_value'}, {'name': 'entry2_name', 'value': 'entry2_value'}]
内容的提问来源于stack exchange,提问作者Marko Todoric
相关产品推荐
相关产品推荐

