fastapi学习文档fastapi

fastapi教程翻译(十三): Response Model(

2019-10-15  本文已影响0人  warmsirius

您可以在任何路径操作中使用参数 response_model 声明用于响应的模型:

一、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

注意

2. response_model功能

FastAPI 将使用 response_model 实现以下功能:

最重要的功能

将输出数据限制为模型的数据.

技术细节
响应模型在此参数中声明,而不是作为函数返回类型注释声明

因为路径函数实际上可能不会返回该响应模型,而是返回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]

但是,如果实际上没有存储它们,则可能要从结果中忽略它们。

例如,如果您的模型在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足够聪明)可以认识到,即使descriptiontaxtags与默认值具有相同的值,它们也是显式设置的(而不是取自默认值) 。

因此,它们将包含在JSON响应中。

注意

默认值可以是任何值,不仅可以是None。
例如可以是一个 list ([]), 一个 float 值为10.5, 等等.

3. response_model_includeresponse_model_exclude

您还可以使用path操作装饰器 参数response_model_includeresponse_model_exclude

他们使用带有属性名称的strstr包括(省略其余部分)或排除(包括其余部分)。

如果您只有一个Pydantic模型,并且想要从输出中删除一些数据,则可以将其用作快速捷径。

注意

但是仍然建议使用上述想法,使用多个类而不是这些参数。

这是因为即使您使用response_model_includeresponse_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而是使用listtuple,则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仅返回显式设置的值。

上一篇下一篇

猜你喜欢

热点阅读