Estoy tratando de usar Literal para crear una unión discriminada con Pydantic. Hay eventos sobre un recurso de trabajo y quiero distinguirlos por event_name . Para JobPublishedEvents , quiero asegurarme de que esté presente algún 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)) # GenericJobEventLos 2 primeros casos se comportan como se esperaba, para el tercero me gustaría un error de validación ya que el literal coincide, pero no se cumple el esquema. Sin embargo, entiendo por qué la alternativa a GenericJobEvent es válida.
¿Alguien tiene una idea sobre cómo lograr esto?
El problema se debe al hecho de que mientras JobPublishedEvent falla, GenericJobEvent no lo hace. Piénsalo, el atributo event_name es una cadena, el id es un int. Todo coincide.
Entonces, lo que podría hacer es validar también event_name en GenericJobEvent y rechazar el nombre de evento job.published
Puede validarlo como se explica en los documentos .
@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()