使用别名时Pydantic抛出额外属性错误,原因是什么?
问题:Pydantic使用别名时,原字段名被判定为额外参数?
代码示例
from typing import Literal from pydantic import BaseModel, Field, ConfigDict class Base(BaseModel): # 让继承类可以像字典一样通过下标访问属性,比如 value = class['key'] def __getitem__(self, item): return getattr(self, item) model_config = ConfigDict(extra='forbid') class Foo(Base): bar: Literal['bar1', 'bar2'] = Field(default=None, frozen=True, alias="bar_path") a = {'bar': 'bar1'} b = Foo(**a)
触发的异常
Traceback (most recent call last): File "/home/hawk/applications/pydantic_example.py", line 16, in <module> b = Foo(**a) ^^^^^^^^ File "/home/hawk/miniconda3/envs/bird/lib/python3.11/site-packages/pydantic/main.py", line 164, in __init__ __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__) pydantic_core._pydantic_core.ValidationError: 1 validation error for Foo bar Extra inputs are not permitted [type=extra_forbidden, input_value='bar1', input_type=str] For further information visit https://errors.pydantic.dev/2.5/v/extra_forbidden
移除别名后代码可正常运行;若保留别名并传入{'bar_path': 'bar1'}也可正常运行。请问为何别名会导致原字段被视为额外参数?
原因分析
这是Pydantic 2.x的默认行为:当你给字段指定alias后,默认只会把别名作为合法的输入键,原字段名不会被自动识别为该字段的输入。而你设置了extra='forbid',禁止额外字段,所以传入原字段名bar时,Pydantic会把它当成未定义的额外字段,触发验证错误。
解决方案
如果需要同时支持原字段名和别名作为输入,只需在model_config中添加populate_by_name=True配置:
class Base(BaseModel): def __getitem__(self, item): return getattr(self, item) # 添加populate_by_name=True,让Pydantic同时识别字段原名和别名 model_config = ConfigDict(extra='forbid', populate_by_name=True) class Foo(Base): bar: Literal['bar1', 'bar2'] = Field(default=None, frozen=True, alias="bar_path") a = {'bar': 'bar1'} b = Foo(**a) # 现在可以正常实例化
这个配置会告诉Pydantic在解析输入数据时,同时匹配字段的原名和别名,这样两种键名都会被正确识别。
内容的提问来源于stack exchange,提问作者alexv9
相关产品推荐
相关产品推荐

