FastAPI 官方文档解读 (二)
Body字段验证
之前我们提到过,Query和Path可以进行字段验证,对长度和取值范围等进行限制。Body中的JSON字段也具有同样的验证,只不过需要声明在Model中,而不是参数中。
class Item(BaseModel):
name: str
description: Optional[str] = Field(
None, title="The description of the item", max_length=300
)
price: float = Field(..., gt=0, description="The price must be greater than zero")
tax: Optional[float] = None
使用Field()
可以很好地满足我们的需求。
复杂类型字段的验证
tags: list = []
表示普通的列表验证,如果我们想要统一的类型(像数组那样),我们可以使用typing的List
来表示,例如tags: List[str] = []
。
你过你要求数据不重复,那么也可以试试set,用typing中的Set
来表示tags: Set[str] = set()
model嵌套
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: Image = None
使用model作为另一个model中字段的类型也是可以的。并且这也将很常用。
特殊类型验证
pydantic提供了一些定义好的特殊类型,方便对各种内容进行验证。
from pydantic import BaseModel, UrlStr
class Image(BaseModel):
url: UrlStr
name: str
UrlStr
便是一种可以验证合法URL的预置类型
列表Body
如果您希望Body中的JSON,最外层是一个列表。那么您需要在参数中像如下一样定义类型。
def create_multiple_images(images: List[Image]):
Dict的Body
除了Model,您也可以使用dict来接收Body。
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
return weights
这种形式的类型标注,即可用字典来接收。当然JSON不支持int类型的key,不用担心,fastapi会自动转换。
Cookie参数
def read_items(*, ads_id: str = Cookie(None)):
像这样声明,即可获取Cookie参数。第一个值为默认值。
Header参数
def read_items(*, user_agent: str = Header(None)):
可以接收Header中的参数。如果Header的一个字段具有多个值,可以使用def read_items(x_token: List[str] = Header(None)):
这种形式
Response model
关于这部分内容,请看前面关于fastapi源码的解读。
model之间的转化
pydantic的model提供了.dict()方法,可以将字段导出为字典。这样便实现模型之间的转换。例如:
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
class UserOut(BaseModel):
username: str
email: EmailStr
这两个model之间的差别只有password,UserIn的定义需要如下形式
user_in = UserIn(
username="john",
password="secret",
email="john.doe@example.com"
)
而UserOut使用dict()导出可能是如下形式
{
'username': 'john',
'email': 'john.doe@example.com',
}
我们只需要user_in = UserIn(**user_out.dict(), password="secret")
便可达到效果
反过来转换,UserIn的dict中多余的参数,会被UserOut忽略掉。
model的Union
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]
Union[PlaneItem, CarItem]
使得response有更多的选择余地。像response_model=List[Item]
也是被允许的
Form表单
= Form(...)
,该类继承于Body
,用法一致。