fastapi教程翻译(十三): Response Model(
您可以在任何路径操作中使用参数 response_model
声明用于响应的模型:
@app.get()
@app.post()
@app.put()
@app.delete()
- etc.
一、response_model
1. 举例
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
是“ decorator”方法(get
,post
等)的参数。 不像所有参数和主体一样,具有路径操作功能。 - 它接收的类型与您为
Pydantic
模型属性声明的类型相同,因此它可以是Pydantic
模型,但也可以是例如 一个Pydantic
模型的清单,例如List [Item]
。
2. response_model
功能
FastAPI 将使用 response_model
实现以下功能:
- 将输出数据转换为其类型声明。
- 验证数据。
- 在OpenAPI路径操作中为响应添加一个JSON模式。
- 将由自动文档系统使用。
最重要的功能:
将输出数据限制为模型的数据.
技术细节
响应模型在此参数中声明,而不是作为函数返回类型注释声明
因为路径函数实际上可能不会返回该响应模型,而是返回
dict
,数据库对象或其他模型,然后使用response_model
,执行字段限制和序列化。
二、返回相同的输入数据
这里我们定义了一个UserIn
模型,它会包含一个纯文本的密码:
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str email: EmailStr
full_name: str = None
# Don't do this in production!
# 不要在生产环境中使用这个!
@app.post("/user/", response_model=UserIn)
async def create_user(*, user: UserIn):
return user
我们正在使用此模型声明输入,并使用同一模型声明输出:
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str = None
# Don't do this in production!
@app.post("/user/", response_model=UserIn) async def create_user(*, user: UserIn):
return user
现在,每当浏览器使用密码创建用户时,API都会在响应中返回相同的密码。
在这种情况下,这可能不是问题,因为用户自己正在发送密码。
但是,如果我们对另一个路径操作使用相同的模型,则可能会将用户的密码发送给每个客户端。
危险
切勿在响应中发送用户的普通密码。
三、添加一个输出模型
我们可以改用纯文本密码创建输入模型,而没有明文密码则创建输出模型:
from pydantic import BaseModel
from pydantic.types import EmailStr
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str = None
在这里,即使我们的路径操作函数正在返回包含密码的相同输入用户:
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import 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
...我们将response_model
声明为我们的模型'UserOut',其中不包含密码:
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import 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
因此,FastAPI 将负责过滤掉未在输出模型中声明的所有数据(使用Pydantic)。
四、查看文档
当您看到自动文档时,可以检查输入模型和输出模型是否都具有自己的JSON模式:
两种模型都将用于交互式API文档:
五、设置响应模型中的参数
1. 响应模型中设置默认值
比如:
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_skip_defaults=True)
async def read_item(item_id: str):
return items[item_id]
-
description: str = None
有默认值None
. -
tax: float = 10.5
有默认值10.5
. -
tags: List[str] = []
有默认值:[]
.
但是,如果实际上没有存储它们,则可能要从结果中忽略它们。
例如,如果您的模型在NoSQL数据库中具有很多可选属性,但是您不想发送很长的JSON响应(包含默认值)。
2. 使用 response_model_skip_defaults
参数
您可以设置 path操作装饰器 参数 response_model_skip_defaults = True
:
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_skip_defaults=True)
async def read_item(item_id: str):
return items[item_id]
这些默认值将不会包含在响应中。
因此,如果您向ID为foo
的项目发送请求到该路径操作,则响应(不包括默认值)将为:
{
"name": "Foo",
"price": 50.2
}
说明
FastAPI使用具有其skip_defaults参数的Pydantic模型的.dict()
来实现此目的。
a. 具有默认值的字段的值的数据
但是如果您的数据具有默认值的模型字段值,例如ID为bar的项目:
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2 }
它们将包含在响应中。
b. 数据具有与默认值相同的值
如果数据具有与默认值相同的值,例如ID为baz
的项:
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
FastAPI足够聪明(实际上,Pydantic足够聪明)可以认识到,即使
description
,tax
和tags
与默认值具有相同的值,它们也是显式设置的(而不是取自默认值) 。
因此,它们将包含在JSON响应中。
注意
默认值可以是任何值,不仅可以是None。
例如可以是一个 list ([]
), 一个float
值为10.5
, 等等.
3. response_model_include
和 response_model_exclude
您还可以使用path操作装饰器 参数response_model_include
和response_model_exclude
。
他们使用带有属性名称的str
集str
来包括(省略其余部分)或排除(包括其余部分)。
如果您只有一个Pydantic
模型,并且想要从输出中删除一些数据,则可以将其用作快速捷径。
注意
但是仍然建议使用上述想法,使用多个类而不是这些参数。
这是因为即使您使用response_model_include
或response_model_exclude
来省略某些属性,在应用程序的OpenAPI(和文档)中生成的JSON模式仍将是完整模型的JSON模式。
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]
注意:
语法{“ name”,“ description”}`用这两个值创建一个set。
相当于
set(["name", "description"])
.
4. 使用 list
代替set
如果您忘记使用set
而是使用list
或tuple
,则FastAPI仍会将其转换为set
,并且可以正常工作:
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_model
定义响应模型,尤其是确保私有数据被过滤掉。
使用response_model_skip_defaults
仅返回显式设置的值。