响应模型
可以在任意路径操作(get,post等)中使用response_model来声明用于返回响应模型
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
需要注意response_model是[装饰器]方法(get,post等)的一个参数,不像之前参数和请求,它不属于路径操作函数
请求体使用UserIn,响应模型使用UserOut,未在输出模型声明的参数都会被过滤掉,示例响应模型会把请求体中的密码给过滤掉。
响应模型编码参数
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: float = 10.5
tags: List[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
return items[item_id]
在item_id都使用foo情况下
response_model_exclude_unset=True:响应会过滤默认值,只返回实际设置的值
{
"name": "Foo",
"price": 50.2
}
response_model_include:需要传一个set(),只显示set中设置的值
{
"name": "Foo",
"description": null
}
response_model_exclude:需要传一个set(),过滤set中设置的值
{
"name": "Foo",
"description": null,
"price": 50.2,
"tags": []
}
通过继承减少重复
对用户模型来说尤其如此,因为:
- 输入模型需要拥有密码属性。
- 输出模型不应该包含密码。
- 数据库模型很可能需要保存密码的哈希值。
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
可以先声明userBase为基础模型,然后创建继承该模型属性(类型声明,校验等)的子类,只要在子类中添加于基础模型不同的字段即可。
多个响应模型
可以将一个响应声明为两种类型的 Union
,这意味着该响应将是两种类型中的任何一种
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type: str = "car"
class PlaneItem(BaseItem):
type: str = "plane"
size: int
items = {
"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])
async def read_item(item_id: str):
return items[item_id]
item_id传item1
{
"description": "All my friends drive a low rider",
"type": "car"
}
item_id传item2
{
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5
}