You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Pydantic对List[Union[PrimaryApplicant, OtherApplicant]]中的isPrimary字段进行鉴别区分?

解决Pydantic Union列表模型匹配错误:用isPrimary字段正确区分主副申请人

这个问题的核心在于Pydantic处理Union类型的默认匹配逻辑:当你定义List[Union[PrimaryApplicant, OtherApplicant]]时,Pydantic会严格按照Union中模型的顺序,逐个尝试解析列表里的每一项。如果第一个模型(PrimaryApplicant)解析失败,才会轮到第二个模型(OtherApplicant)。

但当OtherApplicant缺少必填字段时,Pydantic的匹配流程会出问题:它先尝试用PrimaryApplicant去匹配那个isPrimary=False的项——显然不符合Literal[True]的要求,直接抛出isPrimary值无效的错误;而此时因为前面的匹配已经失败,Pydantic不会再尝试用OtherApplicant去验证,自然也就不会正确提示缺失的必填字段了。


最佳解决方案:使用Pydantic鉴别器(Discriminator)

鉴别器是Pydantic专门为这种有明确区分字段的Union场景设计的功能,它能告诉Pydantic直接通过指定字段的值来选择对应的模型,彻底绕开顺序匹配的坑。

修改后的代码(适配Pydantic v1)

from datetime import date
from pydantic import BaseModel, validator, Field
from typing import List, Literal, Optional, Union

class PrimaryApplicant(BaseModel):
    isPrimary: Literal[True]
    dateOfBirth: Optional[date]

class OtherApplicant(BaseModel):
    isPrimary: Literal[False]
    dateOfBirth: date
    relationshipStatus: Literal["family", "friend", "other", "partner"]

# 定义带鉴别器的Union类型
ApplicationApplicant = Union[PrimaryApplicant, OtherApplicant]

class Application(BaseModel):
    # 通过discriminator指定用isPrimary字段区分模型
    applicants: List[ApplicationApplicant] = Field(..., discriminator="isPrimary")

    @validator("applicants")
    def validate_applicant_limits(cls, v):
        primary_count = sum(1 for applicant in v if applicant.isPrimary)
        secondary_count = len(v) - primary_count
        
        if primary_count > 1:
            raise ValueError("只能有一名主申请人")
        if secondary_count > 1:
            raise ValueError("最多只能有一名其他申请人")
        return v

def main() -> None:
    # 测试:OtherApplicant缺失dateOfBirth字段
    data_dict = {
        "applicants": [
            {"isPrimary": True},
            {"isPrimary": False, "relationshipStatus": "family"}  # 缺失dateOfBirth
        ]
    }
    try:
        Application(**data_dict)
    except Exception as e:
        print(e)

if __name__ == "__main__":
    main()

效果验证

现在当OtherApplicant缺失必填字段时,错误提示会准确指向缺失的字段,不会再出现isPrimary的误报:

pydantic.error_wrappers.ValidationError: 1 validation error for Application
applicants -> 1 -> dateOfBirth
  field required (type=value_error.missing)

补充:Pydantic v2的写法

如果你用的是Pydantic v2,语法会稍有调整,推荐用Annotated来结合鉴别器:

from datetime import date
from pydantic import BaseModel, field_validator, Field
from typing import List, Literal, Optional, Union
from typing_extensions import Annotated

class PrimaryApplicant(BaseModel):
    isPrimary: Literal[True]
    dateOfBirth: Optional[date]

class OtherApplicant(BaseModel):
    isPrimary: Literal[False]
    dateOfBirth: date
    relationshipStatus: Literal["family", "friend", "other", "partner"]

# 用Annotated指定鉴别器
ApplicationApplicant = Annotated[
    Union[PrimaryApplicant, OtherApplicant],
    Field(discriminator="isPrimary")
]

class Application(BaseModel):
    applicants: List[ApplicationApplicant]

    @field_validator("applicants")
    def validate_applicant_limits(cls, v):
        primary_count = sum(1 for applicant in v if applicant.isPrimary)
        secondary_count = len(v) - primary_count
        
        if primary_count > 1:
            raise ValueError("只能有一名主申请人")
        if secondary_count > 1:
            raise ValueError("最多只能有一名其他申请人")
        return v

核心逻辑和v1一致,都是通过discriminator指定区分字段,让Pydantic直接匹配对应模型。


内容的提问来源于stack exchange,提问作者anon_dcs3spp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:12:41