【问题标题】:Pydantic: Validate discriminated union with literalsPydantic:使用文字验证有区别的联合
【发布时间】:2020-06-23 07:49:34
【问题描述】:

我正在尝试使用Literal 与 Pydantic 创建一个有区别的联合。 有关于 Job 资源的事件,我想通过event_name 来区分它们。对于JobPublishedEvents,我想确保存在一些extra_field。

class GenericJobEvent(BaseModel):
    event_name: str
    id: int


class JobPublishedEvent(GenericJobEvent):
    event_name: Literal['job.published']
    extra_field: str


class Wrapper(BaseModel):
    wrapped: Union[JobPublishedEvent, GenericJobEvent]

print(type(Wrapper(wrapped={'event_name': 'some.event', 'id': 1}).wrapped))  # GenericJobEvent
print(type(Wrapper(wrapped={'event_name': 'job.published', 'id': 1, 'extra_field': 'extra'}).wrapped))  # JobPublishedEvent
print(type(Wrapper(wrapped={'event_name': 'job.published', 'id': 1}).wrapped))  # GenericJobEvent

前两种情况的行为符合预期,对于第三种情况,我想要一个验证错误,因为文字匹配,但架构不满足。不过,我明白为什么回退到 GenericJobEvent 是有效的。

有人知道如何实现这一目标吗?

【问题讨论】:

    标签: python discriminated-union fastapi pydantic


    【解决方案1】:

    问题是由于JobPublishedEvent 失败,GenericJobEvent 没有。想想看,event_name 属性是一个字符串,id 是一个 int。一切都匹配。

    因此,您可以做的就是验证GenericJobEvent 中的event_name 并拒绝事件名称job.published

    您可以按照docs中的说明进行验证

    @validator('event_name')
        def event_name_filter(cls, v):
            if 'job.published' == v:
                raise ValueError('GenericJobEvent cannot have event_name equal to job.published')
            return v.title()
    

    【讨论】:

    • 是的,这就是我所说的“我明白为什么回退到 GenericJobEvent 是有效的”的意思。我需要的是 GenericEvent 接受除子类中定义的字符串之外的所有字符串...谢谢您的解决方案!
    • 抱歉,过多的多任务处理导致我分心。很高兴我有帮助
    猜你喜欢
    • 1970-01-01
    • 2021-02-14
    • 2019-09-04
    • 2023-02-09
    • 2013-08-11
    • 1970-01-01
    • 2023-01-05
    • 1970-01-01
    • 2018-11-24
    相关资源
    最近更新 更多