背景

在开发过程中,由于上游数据结构可能存在不一致的情况,例如字段名称不同但含义相同(如有时上游数据中的字段名为 id,有时为 code),为了避免手动编写大量重复代码,我们可以利用 Pydantic 提供的功能,轻松处理这些差异。

Pydantic 允许通过别名(alias)进行字段映射,从而解决不同字段名但含义相同的情况,有效减少代码复杂度。

解决方案

旧版本处理方案(Pydantic v1.x)

在 Pydantic v1.x 中,使用 alias 配合 allow_population_by_field_name 选项来实现字段兼容:

from pydantic import BaseModel, Field
​
class Foo(BaseModel):
    id: int = Field(..., alias="item_id")
    field1: str
    
    class Config:
        # 允许通过别名或字段名进行数据填充
        allow_population_by_field_name = True
​
# 测试兼容性
foo1 = Foo.parse_obj({"item_id": 123, "field1": "value1"})
foo2 = Foo.parse_obj({"id": 234, "field1": "value1"})
​
print(foo1)  # Foo(id=123, field1='value1')
print(foo2)  # Foo(id=234, field1='value1')

新版本处理方案(Pydantic v2.x)

Pydantic v2.x 对配置做了一些调整,将 allow_population_by_field_name 替换为 populate_by_name。新的配置更加简洁,也引入了新的验证方法。

官方文档参考:Pydantic 配置文档

方案一:通过 Config 配置类

from pydantic import BaseModel, Field
​
class Foo(BaseModel):
    id: int = Field(..., alias="item_id")
    field1: str
    
    class Config:
        # 使用字段名称进行填充
        populate_by_name = True
​
# 测试兼容性
foo1 = Foo.model_validate({"item_id": 123, "field1": "value1"})
foo2 = Foo.model_validate({"id": 234, "field1": "value1"})
​
print(foo1)  # Foo(id=123, field1='value1')
print(foo2)  # Foo(id=234, field1='value1')

方案二:通过 ConfigDict

Pydantic v2.x 提供了 ConfigDict 来配置模型行为,使用方式如下:

from pydantic import BaseModel, Field, ConfigDict
​
class Foo(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    id: int = Field(..., alias="item_id")
    field1: str
​
# 测试兼容性
foo1 = Foo.model_validate({"item_id": 123, "field1": "value1"})
foo2 = Foo.model_validate({"id": 234, "field1": "value1"})
​
print(foo1)  # Foo(id=123, field1='value1')
print(foo2)  # Foo(id=234, field1='value1')

结果说明

无论上游传递的字段名是 item_id 还是 id,通过设置 alias 和启用 populate_by_name 配置,都可以兼容不同的字段名称,同时确保数据的一致性。这种方法特别适合处理复杂的、变化频繁的上游接口数据。