FastAPI Response(一) Response模型
作者:麦克煎蛋 出处:https://www.cnblogs.com/mazhiyong/ 转载请保留这段声明,谢谢!
一、Response模型
在路径操作中,我们可以用参数response_model
来声明Response模型。
from typing import List from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str = None price: float tax: float = None tags: List[str] = [] @app.post("/items/", response_model=Item) async def create_item(item: Item): return item
注意response_model
是装饰器方法(get,post等)的参数。
Response模型可以是一个Pydantic模型,也可以是一个Pydantic模型的列表,例如List[Item]。
支持任意路径操作:
@app.get()
@app.post()
@app.put()
@app.delete()
FastAPI利用Response模型实现以下功能:
1、将输出数据转换成声明的Response模型。
2、对数据进行校验
3、生成自动化文档
4、(最重要的)限制输出数据只能是所声明的Response模型。
二、输入输出模型示例
# 可能需要安装email-validator --> pip install email-validator
from fastapi import FastAPI from pydantic import BaseModel, EmailStr app = FastAPI() class UserIn(BaseModel): username: str password: str email: EmailStr full_name: str = None class UserOut(BaseModel): username: str email: EmailStr full_name: str = None @app.post("/user/", response_model=UserOut) async def create_user(*, user: UserIn): return user
如上所示,虽然路径操作函数返回的结果是user(包含了password),但我们声明的Response模型是UserOut(不包含password)。
FastAPI会过滤掉所有不在输出模型中的数据,因此最终的输出结果里并没有password。
如果输入内容如下:
{ "username": "user", "password": "1234", "email": "user@qq.com", "full_name": "full_name" }
那么输出结果为:
{ "username": "user", "email": "user@qq.com", "full_name": "full_name" }
三、Response模型参数
1、Response模型可以有缺省值。
from typing import List from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str = 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]
2、返回实际有效数据
有时候我们只想返回被真正设置过的数据,而忽略其他未被设置过的或者缺省数据。
我们可以用参数response_model_exclude_unset来实现这个目的。
如上所示代码。
# 访问:
http://127.0.0.1:8000/items/foo
# 返回结果:
{
"name": "Foo",
"price": 50.2
}
3、参数 response_model_include
和 response_model_exclude
这两个参数接收Response模型的部分属性集合,分别表示包含(排除剩下的)和排除(包含剩下的)集合里的属性。
在实际工作中,我们应该尽量少利用这两个参数,而是应该声明不同的类表示不同的数据需求,这样更利于数据维护和逻辑清晰。
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str = None price: float tax: float = 10.5 items = { "foo": {"name": "Foo", "price": 50.2}, "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, "baz": { "name": "Baz", "description": "There goes my baz", "price": 50.2, "tax": 10.5, }, } @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]
四、Response联合模型
我们可以声明Response模型是一个Union类型(包含两种类型),实际返回结果可以是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 = "car" class PlaneItem(BaseItem): type = "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]
这里PlaneItem、CarItem均从BaseItem继承而来,提高代码复用,也便于代码维护。
五、Response列表模型
Response模型也可以是一个列表。
from typing import List from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: str items = [ {"name": "Foo", "description": "There comes my hero"}, {"name": "Red", "description": "It's my aeroplane"}, ] @app.get("/items/", response_model=List[Item]) async def read_items(): return items
六、Response字典模型
我们也可以不用Pydantic模型,而是直接基于字典来声明Response模型。
from typing import Dict from fastapi import FastAPI app = FastAPI() @app.get("/keyword-weights/", response_model=Dict[str, float]) async def read_keyword_weights(): return {"foo": 2.3, "bar": 3.4}