如何在FastAPI主体验证中使用区分的并集类型?(型号为Union)



我从Typescript中知道一个名为判别并集的概念。这是一个放置2个结构(类等(的地方,类型取决于结构的值。我正试图通过Pydantic验证在FastAPI中实现类似的功能。我可以收到两种不同的请求有效载荷。是一个还是另一个取决于accountType变量。如果是creative,则应通过RegistrationPayloadCreative进行验证;如果是brand,则应由RegistrationPayloadBrand进行验证。我该如何做到这一点?找不到任何其他解决方案。

问题是它要么返回

unexpected value; permitted: 'creative' (type=value_error.const; given=brand; permitted=('creative',))

或者根本不起作用。

class RegistrationPayloadBase(BaseModel):
    first_name: str
    last_name: str
    email: str
    password: str

class RegistrationPayloadCreative(RegistrationPayloadBase):
    accountType: Literal['creative']

class RegistrationPayloadBrand(RegistrationPayloadBase):
    company: str
    phone: str
    vat: str
    accountType: Literal['brand']
class A(BaseModel):
    b: Union[RegistrationPayloadBrand, RegistrationPayloadCreative]
def main():
    A(b={'first_name': 'sdf', 'last_name': 'sdf', 'email': 'sdf', 'password': 'sdfds', 'accountType': 'brand'})
if __name__ == '__main__':
    main()

您应该使用__root__parse_obj

from typing import Union
from pydantic import BaseModel

class PlanetItem(BaseModel):
    id: str
    planet_name: str 
    # ...
class CarItem(BaseModel):
    id: str
    name: str
    # ...
class EitherItem(BaseModel):
    __root__: Union[PlanetItem, CarItem]

@app.get("/items/{item_id}", response_model=EitherItem)
def get_items(item_id):
    return EitherItem.parse_obj(response) # Now you get either PlanetItem or CarItem

信用:https://github.com/tiangolo/fastapi/issues/2279#issuecomment-787517707

错误消息有点误导,因为问题是RegistrationPayloadBrand中的company/phone/vat字段是强制性的。

因此:

 >>> A(b={'first_name': 'sdf', 'last_name': 'sdf', 'email': 'sdf', 'password': 'sdfds', 'accountType': 'brand', 'company':'foo','vat':'bar', 'phone':'baz'}) 
A(b=RegistrationPayloadBrand(first_name='sdf', last_name='sdf',
email='sdf', password='sdfds', company='foo', phone='baz', vat='bar', accountType='brand'))
>>> A(b={'first_name': 'sdf', 'last_name': 'sdf', 'email': 'sdf', 'password': 'sdfds', 'accountType': 'creative'})
A(b=RegistrationPayloadCreative(first_name='sdf', last_name='sdf', email='sdf', password='sdfds', accountType='creative'))

或者使其可选(如果有效载荷不一定包含这些字段(

class RegistrationPayloadBrand(RegistrationPayloadBase):
    company: Optional[str]
    phone:   Optional[str]
    vat:     Optional[str]
    accountType: Literal['brand']
>>> A(b={'first_name': 'sdf', 'last_name': 'sdf', 'email': 'sdf', 'password': 'sdfds', 'accountType': 'brand'})
A(b=RegistrationPayloadBrand(first_name='sdf', last_name='sdf', email='sdf', password='sdfds', company=None, phone=None, vat=None, accountType='brand'))
>>> A(b={'first_name': 'sdf', 'last_name': 'sdf', 'email': 'sdf', 'password': 'sdfds', 'accountType': 'creative'})
A(b=RegistrationPayloadCreative(first_name='sdf', last_name='sdf', email='sdf', password='sdfds', accountType='creative'))

将解决问题

相关内容

  • 没有找到相关文章

最新更新