我有以下 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,
}
但是,当我尝试将值加载到 pydantic 模型中时,data['msg']
被转换为单个字典而不是字典列表。
>>> msg = WSMessage(**data)
>>> msg
WSMessage(
action='reply',
success=True,
sent_from='jumphost',
send_to='46.235.96.113_UE4yWw69iSBEf67JhhWTpg==',
data=None,
msg={'name': 'value'},
reason=None,
completed=True,
to_action='get_system_properties'
)
>>> msg.msg
{'name': 'value'}
我做错了什么?我希望 msg
接受任何形式的数据。或者更具体地说,字符串、字典或列表。
如果我从模型中删除 'msg'
,它会正确地将其解析为字典列表。
最佳答案
您的代码几乎可以工作。首先,您应该使用 List[dict]
而不是 List
,因为它更精确。其次,当您使用Union
定义字段时,pydantic将按照并集的顺序进行匹配(第一个匹配的数据结构)。
编写代码时:
msg: Optional[Union[str, Dict, List[Dict]] = None
给定一个字典列表,pydantic 将尝试将您的值强制转换为 dict
(在尝试 dict
列表之前) - 因为列表中的第一个对象是一个字典,它可以成功地强制它并完成。
如果切换联合的顺序:
msg: Optional[Union[str, List[Dict], Dict]] = None
Pydantic 现在将首先检查该值是否是字典列表,然后再解析以匹配字典。现在应该可以了。
相关:受歧视的工会是 pydantic 中经常争论的话题:
关于python - Pydantic 字典列表通过其键转换为单个字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75399828/