fastapi教程-进阶五(Response Model)

参考内容

Response Model

还是以一个例子开头:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
    return user

我们可以在下面这几个操作中用response_model参数来声明响应的模板结构:

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()
  • 其他请求类型

FastAPI将使用response_model进行以下操作:

  • 将输出数据转换为response_model中声明的数据类型。
  • 验证数据结构和类型
  • 将输出数据限制为该model定义的
  • 添加到OpenAPI中
  • 在自动文档系统中使用。

我们尝试启动上面这个例子的服务,并通过POST请求http://127.0.0.1:8000/user/,我们可以看到返回和请求体是一样的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1sVQyk8E-1599029098971)(evernotecid://FBE381A3-17C7-41D9-AA37-9C5F29FAB396/appyinxiangcom/20545635/ENResource/p216)]

不难发现这里有一个问题,如果我们用同一个model去声明请求体参数和响应model,会造成password的泄露,那么,我们来尝试不让password返回:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

这里我们定义了两个model(UserIn和UserOut)分别用在请求体参数和响应model,再次请求http://127.0.0.1:8000/user/,这时我们发现响应已经没有password了:

{
  "username": "string",
  "email": "user@example.com",
  "full_name": "string"
}
response_model_exclude_unset

通过上面的例子,我们学到了如何用response_model控制响应体结构,但是如果它们实际上没有存储,则可能要从结果中忽略它们。

例如,如果model在NoSQL数据库中具有很多可选属性,但是不想发送很长的JSON响应,其中包含默认值。

我们来看一个例子:

from typing import List, Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[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]

我们发现,get操作中多了response_model_exclude_unset属性,他是用来控制什么的呢?

尝试请求http://127.0.0.1:8000/items/foo,结果返回了这样的数据:

{
  "name": "Foo",
  "price": 50.2
}

通过前面的学习,我们知道response的结构应该是这样的:

{
  "name": "string",
  "description": "string",
  "price": 0,
  "tax": 0,
  "tags": [
    "string"
  ]
}

这就是response_model_exclude_unset发挥了作用。response_model_exclude_unset可以控制不返回没有设置的参数。
当然,除了response_model_exclude_unset以外,还有response_model_exclude_defaultsresponse_model_exclude_none,我们可以很直观的了解到他们的意思,不返回是默认值的字段和不返回是None的字段,下面让我们分别尝试一下

设置response_model_exclude_defaults=True, 请求http://127.0.0.1:8000/items/baz,返回:

{
  "name": "Baz",
  "price": 50.2
}

设置response_model_exclude_none=True, 请求http://127.0.0.1:8000/items/baz,返回:

{
  "name": "Baz",
  "price": 50.2,
  "tax": 10.5,
  "tags": []
}

注意:response_model_exclude_defaults控制了不返回是默认值的字段,这个默认值不仅仅是None,他可能是我们在model中设置的任意一个值

response_model_include和response_model_exclude

接下来我们学习如何用response_model_includeresponse_model_exclude来控制响应参数,不难理解这两个参数的意思分别是响应参数包括哪些和不包括哪些,我们还是从实例看看他们是如何使用的:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[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": "string",
  "description": "string",
  "price": 0,
  "tax": 0
}

那么,我们来尝试一下请求http://127.0.0.1:8000/items/foo/name, 返回:

{
  "name": "Foo",
  "description": null
}

为什么只返回了namedescription呢?因为我们在参数中添加了response_model_include={"name", "description"},它控制了响应参数只包括namedescription
再次尝试请求http://127.0.0.1:8000/items/bar/public,返回:

{
  "name": "Bar",
  "description": "The Bar fighters",
  "price": 62
}

为什么没有返回tax呢?这时因为我们在参数中添加了response_model_exclude={"tax"},它控制了想响应参数除了tax都要返回。

除了用set来声明response_model_excluderesponse_model_include,也可以用listtuple,fastapi会将他们专程set类型

总结

  1. 使用路径操作装饰器的参数response_model定义响应模型,确保私有数据被过滤掉
  2. 使用路径操作装饰器的参数response_model_exclude_unsetresponse_model_exclude_defaultsresponse_model_exclude_none来过滤掉符合条件的参数
  3. 使用路径操作装饰器的参数response_model_includeresponse_model_exclude来指定字段进行过滤

上述栗子均放到git上啦,地址:戳这里

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果你想要自定义 FastAPIresponse_model 参数来返回一个 JSON 数组,你可以使用 List[Response[Dict[str, Any]]] 来实现。这里的 Dict[str, Any] 表示返回的 JSON 对象可以包含任意的键值对,具体的键和值可以根据你的需要进行定义,示例代码如下: ```python from typing import Generic, List, TypeVar, Dict, Any from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() T = TypeVar('T') class Response(Generic[T]): data: T code: int = 0 msg: str = "success" class User(BaseModel): name: str age: int @app.get("/users/", response_model=List[Response[Dict[str, Any]]]) async def read_users(): users = [{"name": "Alice", "age": 20}, {"name": "Bob", "age": 25}] response = [Response[Dict[str, Any]](data=user_dict) for user_dict in users] return response ``` 在这个示例代码,我们使用了一个类似于之前的 Response 泛型类,但是 data 属性的类型是 Dict[str, Any],这样就可以包含任意的键值对。在 read_users 函数,我们使用了 List[Response[Dict[str, Any]]] 作为 response_model 参数,表示返回一个 Response 泛型类的列表,每个 Response 对象的 data 属性都是一个包含任意键值对的字典。我们根据实际数据构造了一个 Response 泛型类的列表,并将其作为返回值。 使用这种方式可以方便地自定义返回的 JSON 数组,可以根据实际需要定义不同的 Response 类型,以及每个 Response 对象的 data 属性的键值对。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值