Se tomarmos um dict como user_dict e passarmos para uma função (ou classe) com **user_dict, o Python irá "desembrulhá-lo". Ele passará as chaves e valores do user_dict diretamente como argumentos chave-valor.
Então, continuando com o user_dict acima, escrevendo:
Reduzir a duplicação de código é uma das ideias principais no FastAPI.
A duplicação de código aumenta as chances de bugs, problemas de segurança, problemas de desincronização de código (quando você atualiza em um lugar, mas não em outros), etc.
E esses modelos estão compartilhando muitos dos dados e duplicando nomes e tipos de atributos.
Nós poderíamos fazer melhor.
Podemos declarar um modelo UserBase que serve como base para nossos outros modelos. E então podemos fazer subclasses desse modelo que herdam seus atributos (declarações de tipo, validação, etc.).
Toda conversão de dados, validação, documentação, etc. ainda funcionará normalmente.
Dessa forma, podemos declarar apenas as diferenças entre os modelos (com password em texto claro, com hashed_password e sem senha):
Você pode declarar uma resposta como o Union de dois tipos, o que significa que a resposta seria qualquer um dos dois.
Isso será definido no OpenAPI com anyOf.
Para fazer isso, use a dica de tipo padrão do Python typing.Union:
Note
Ao definir um Union, inclua o tipo mais específico primeiro, seguido pelo tipo menos específico. No exemplo abaixo, o tipo mais específico PlaneItem vem antes de CarItem em Union[PlaneItem, CarItem].
fromtypingimportUnionfromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classBaseItem(BaseModel):description:strtype:strclassCarItem(BaseItem):type:str="car"classPlaneItem(BaseItem):type:str="plane"size:intitems={"item1":{"description":"All my friends drive a low rider","type":"car"},"item2":{"description":"Music is my aeroplane, it's my aeroplane","type":"plane","size":5,},}@app.get("/items/{item_id}",response_model=Union[PlaneItem,CarItem])asyncdefread_item(item_id:str):returnitems[item_id]
fromtypingimportUnionfromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classBaseItem(BaseModel):description:strtype:strclassCarItem(BaseItem):type:str="car"classPlaneItem(BaseItem):type:str="plane"size:intitems={"item1":{"description":"All my friends drive a low rider","type":"car"},"item2":{"description":"Music is my aeroplane, it's my aeroplane","type":"plane","size":5,},}@app.get("/items/{item_id}",response_model=Union[PlaneItem,CarItem])asyncdefread_item(item_id:str):returnitems[item_id]
Neste exemplo, passamos Union[PlaneItem, CarItem] como o valor do argumento response_model.
Dado que estamos passando-o como um valor para um argumento em vez de colocá-lo em uma anotação de tipo, precisamos usar Union mesmo no Python 3.10.
Se estivesse em uma anotação de tipo, poderíamos ter usado a barra vertical, como:
some_variable:PlaneItem|CarItem
Mas se colocarmos isso em response_model=PlaneItem | CarItem teríamos um erro, pois o Python tentaria executar uma operação inválida entre PlaneItem e CarItem em vez de interpretar isso como uma anotação de tipo.
Da mesma forma, você pode declarar respostas de listas de objetos.
Para isso, use o padrão Python typing.List (ou simplesmente list no Python 3.9 e superior):
fromtypingimportListfromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:stritems=[{"name":"Foo","description":"There comes my hero"},{"name":"Red","description":"It's my aeroplane"},]@app.get("/items/",response_model=List[Item])asyncdefread_items():returnitems
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:stritems=[{"name":"Foo","description":"There comes my hero"},{"name":"Red","description":"It's my aeroplane"},]@app.get("/items/",response_model=list[Item])asyncdefread_items():returnitems
Use vários modelos Pydantic e herde livremente para cada caso.
Não é necessário ter um único modelo de dados por entidade se essa entidade precisar ter diferentes "estados". No caso da "entidade" de usuário com um estado que inclui password, password_hash e sem senha.