我从 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
所以:
>>> 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'))
就能解决问题