如何在Pydantic模型中互换使用字段原名与别名访问属性?
实现Pydantic模型字段原名与别名双向访问
这个需求完全可行,下面提供两种实用方案,解决别名无法直接访问属性的问题:
方案一:重写__getattr__和__setattr__(通用方案)
通过重写模型的属性访问/赋值魔法方法,让别名自动映射到对应字段的原名,无需为每个字段单独配置,适合多字段场景:
from pydantic import BaseModel, Field, model_fields class Item(BaseModel): name: str = Field(alias='identifier') price: float = Field(alias='cost') model_config = {'populate_by_name': True} def __getattr__(self, name): # 遍历字段,检查当前访问的名称是否是某个字段的别名 for field_name, field in model_fields[self.__class__].items(): if field.alias == name: return getattr(self, field_name) raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") def __setattr__(self, name, value): # 处理别名赋值,映射到对应字段原名 for field_name, field in model_fields[self.__class__].items(): if field.alias == name: super().__setattr__(field_name, value) return super().__setattr__(name, value) # 测试验证 r2 = Item(name="test_item", cost=29.9) print(r2.name) # 输出 test_item print(r2.identifier) # 输出 test_item print(r2.price) # 输出 29.9 print(r2.cost) # 输出 29.9 # 别名赋值也生效 r2.identifier = "updated_item" r2.cost = 19.9 print(r2.name) # 输出 updated_item print(r2.price) # 输出 19.9
注意:如果使用Pydantic v1版本,将model_fields替换为__fields__即可。
方案二:单个字段用@property(适合少量字段)
如果模型中需要别名的字段不多,可以直接用属性装饰器手动映射,语义更直观:
from pydantic import BaseModel, Field class Item(BaseModel): name: str = Field(alias='identifier') model_config = {'populate_by_name': True} @property def identifier(self): return self.name @identifier.setter def identifier(self, value): self.name = value # 测试 r2 = Item(name="test") print(r2.identifier) # 输出 test r2.identifier = "new_test" print(r2.name) # 输出 new_test
两种方案都能实现原名与别名的双向访问/赋值,方案一通用性更强,无需重复编写代码;方案二更适合字段少的场景,代码可读性更高,都比@computed_field的语义更贴合“别名作为字段访问入口”的需求。
内容的提问来源于stack exchange,提问作者Guillaume
相关产品推荐
相关产品推荐

