FastAPI 教程翻译 - 用户指南 15 - 响应模型
FastAPI Tutorial - User Guide - Response Model
You can declare the model used for the response with the parameter response_model
in any of the path operations:
您可以在任何路径操作中使用参数 response_model
声明用于响应的模型:
-
@app.get()
-
@app.post()
-
@app.put()
-
@app.delete()
-
etc.
等等。
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
Note
注意
Notice that
response_model
is a parameter of the “decorator” method (get
,post
, etc). Not of your path operation function, like all the parameters and body.请注意,
response_model
是『装饰器』方法的参数(get
、post
等)。像所有参数和主体一样,不是路径操作函数。
It receives the same type you would declare for a Pydantic model attribute, so, it can be a Pydantic model, but it can also be, e.g. a list
of Pydantic models, like List[Item]
.
它收到的类型与您为 Pydantic 模型属性声明的类型相同,因此它可以是 Pydantic 模型,但也可以是一个 Pydantic 模型的列表,像 List[Item]
。
FastAPI will use this response_model
to:
FastAPI 将使用此 response_model
来:
-
Convert the output data to its type declaration.
将输出数据转换为其类型声明。
-
Validate the data.
验证数据。
-
Add a JSON Schema for the response, in the OpenAPI path operation.
在 OpenAPI 的路径操作中为响应添加 JSON 模式。
-
Will be used by the automatic documentation systems.
将由自动文档系统使用。
But most importantly:
但最重要的是:
-
Will limit the output data to that of the model. We’ll see how that’s important below.
将输出数据限制为模型的数据。我们将在下面看到其重要性。
Technical Details
技术细节
The response model is declared in this parameter instead of as a function return type annotation, because the path function may not actually return that response model but rather return a
dict
, database object or some other model, and then use theresponse_model
to perform the field limiting and serialization.在此参数中声明响应模型,而不是将其声明为函数返回类型注释,因为路径函数实际上可能不会返回该响应模型,而是返回
dict
、数据库对象或其他模型,然后使用response_model
执行字段限制和序列化。
Return the same input data
返回相同的输入数据
Here we are declaring a UserIn
model, it will contain a plaintext password:
在这里,我们声明一个 UserIn 模型,它将包含一个纯文本密码:
from fastapi import FastAPI
from pydantic import BaseModel, 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
And we are using this model to declare our input and the same model to declare our output:
我们正在使用此模型声明输入,并使用同一模型声明输出:
from fastapi import FastAPI
from pydantic import BaseModel, 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
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
现在,每当浏览器使用密码创建用户时,API 都会在响应中返回相同的密码。
In this case, it might not be a problem, because the user himself is sending the password.
在这种情况下,这可能不是问题,因为用户自己正在发送密码。
But if we use the same model for another path operation, we could be sending our user’s passwords to every client.
但是,如果我们对另一个路径操作使用相同的模型,则可能会将用户的密码发送给每个客户端。
Danger
危险
Never send the plain password of a user in a response.
切勿在响应中发送用户的明文密码。
Add an output model
添加输出模型
We can instead create an input model with the plaintext password and an output model without it:
我们可以改用纯文本密码创建输入模型,而没有明文密码的方式创建输出模型:
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
Here, even though our path operation function is returning the same input user that contains the password:
在这里,即使我们的路径操作函数返回的是包含密码的相同的输入用户:
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
…we declared the response_model
to be our model UserOut
, that doesn’t include the password:
…… 我们声明 response_model
为我们的模型 UserOut
,其中不包含密码:
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
So, FastAPI will take care of filtering out all the data that is not declared in the output model (using Pydantic).
因此,FastAPI 将负责过滤掉未在输出模型中声明的所有数据(使用 Pydantic)。
See it in the docs
在文档中查看
When you see the automatic docs, you can check that the input model and output model will both have their own JSON Schema:
当您查看自动文档时,可以检查输入模型和输出模型是否都具有自己的 JSON 模式:
And both models will be used for the interactive API documentation:
两种模型都将用于交互式 API 文档:
Response Model encoding parameters
响应模型编码参数
Your response model could have default values, like:
您的响应模型可能具有默认值,例如:
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]
-
description: str = None
has a default ofNone
.description: str = None
的默认值为None
。 -
tax: float = 10.5
has a default of10.5
.tax: float = 10.5
的默认值为10.5
。 -
tags: List[str] = []
has a default of an empty list:[]
.tags: List[str] = []
的默认值为空列表:[]
.
but you might want to omit them from the result if they were not actually stored.
但是如果它们实际上没有存储,则可能要从结果中忽略它们。
For example, if you have models with many optional attributes in a NoSQL database, but you don’t want to send very long JSON responses full of default values.
例如,如果您的模型在 NoSQL 数据库中具有很多可选属性,但您不想发送其中包含默认值的很长的 JSON 响应。
Use the response_model_exclude_unset
parameter
使用 response_model_exclude_unset
参数
You can set the path operation decorator parameter response_model_exclude_unset=True
:
您可以设置路径操作装饰器参数 response_model_exclude_unset=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_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
and those default values won’t be included in the response, only the values actually set.
而这些默认值将不包括在响应中,仅包含实际设置的值。
So, if you send a request to that path operation for the item with ID foo
, the response (not including default values) will be:
因此,如果您向路径操作发送 ID 为 foo
的请求,则响应(不包括默认值)将为:
{
"name": "Foo",
"price": 50.2
}
Info
信息
FastAPI uses Pydantic model’s
.dict()
with itsexclude_unset
parameter to achieve this.FastAPI 使用 Pydantic 模型的
.dict()
和 其exclude_unset参数 来实现此目的。
Data with values for fields with defaults
具有默认值的字段的值的数据
But if your data has values for the model’s fields with default values, like the item with ID bar
:
但是,如果您的数据中包含默认值的模型字段值,例如 ID 为 bar
的项目:
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2
}
they will be included in the response.
它们将包含在响应中。
Data with the same values as the defaults
数据具有与默认值相同的值
If the data has the same values as the default ones, like the item with ID baz
:
如果数据的值与默认值相同,例如 ID 为 baz
的项目:
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
FastAPI is smart enough (actually, Pydantic is smart enough) to realize that, even though description
, tax
, and tags
have the same values as the defaults, they were set explicitly (instead of taken from the defaults).
FastAPI 足够聪明(实际上是,Pydantic 足够聪明)可以意识到,即使 description
、tax
、tags
具有与默认值相同的值,它们也是显式设置的(而不是取自默认值)。
So, they will be included in the JSON response.
因此,它们将包含在 JSON 响应中。
Tip
提示
Notice that the default values can be anything, not only
None
.请注意,默认值可以是任何值,不仅可以是 None。
They can be a list (
[]
), afloat
of10.5
, etc.它们可以是列表(
[]
)或者10.5
这样的float
等等。
response_model_include
and response_model_exclude
response_model_include
和 response_model_exclude
You can also use the path operation decorator parameters response_model_include
and response_model_exclude
.
您还可以使用路径操作装饰器参数 response_model_include
和 response_model_exclude
。
They take a set
of str
with the name of the attributes to include (omitting the rest) or to exclude (including the rest).
它们使用带有属性名称的 str
的 set
集合来包括(省略其余部分)或排除(包括其余部分)。
This can be used as a quick shortcut if you have only one Pydantic model and want to remove some data from the output.
如果您只有一个 Pydantic 模型,并且想要从输出中删除一些数据,可以将其用作快速捷径。
Tip
提示
But it is still recommended to use the ideas above, using multiple classes, instead of these parameters.
但是,仍然建议使用上述思路,使用多个类,而不是这些参数。
This is because the JSON Schema generated in your app’s OpenAPI (and the docs) will still be the one for the complete model, even if you use
response_model_include
orresponse_model_exclude
to omit some attributes.这是因为即使您使用
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]
Tip
提示
The syntax
{"name", "description"}
creates aset
with those two values.语法
{"name", "description"}
用这两个值创建一个set
。It is equivalent to
set(["name", "description"])
.等效于
set(["name", "description"])
。
Using list
s instead of set
s
使用 list
代替 set
If you forget to use a set
and use a list
or tuple
instead, FastAPI will still convert it to a set
and it will work correctly:
如果您忘记使用 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]
Recap
回顾
Use the path operation decorator’s parameter response_model
to define response models and especially to ensure private data is filtered out.
使用路径操作装饰器的参数 response_model
定义响应模型,尤其是确保私有数据被过滤掉。
Use response_model_exclude_unset
to return only the values explicitly set.
使用 response_model_exclude_unset
只返回显式设置的值。