zoukankan      html  css  js  c++  java
  • FastAPI(19)- Response Model 响应模型

    前言

    • 前面文章写的这么多路径函数最终 return 的都是自定义结构的字典
    • FastAPI 提供了 response_model 参数,声明 return 响应体的模型

    什么是路径操作、路径函数

    # 路径操作
    @app.post("/items/", response_model=Item)
    # 路径函数
    async def create_item(item: Item):
        ...

    重点

    response_model 是路径操作的参数,并不是路径函数的参数哦

    • @app.get()
    • @app.post()
    • @app.put()
    • @app.delete()

    最简单的栗子

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/9/21 5:12 下午
    # file: 17_response_model.py
    """
    
    from typing import List, Optional
    
    import uvicorn
    from fastapi import FastAPI
    from pydantic import BaseModel
    
    app = FastAPI()
    
    
    class Item(BaseModel):
        name: str
        description: Optional[str] = None
        price: float
        tax: Optional[float] = None
        tags: List[str] = []
    
    
    @app.post("/items/", response_model=Item)
    async def create_item(item: Item):
        return item
    
    
    if __name__ == "__main__":
        uvicorn.run(app="16_Header:app", host="127.0.0.1", port=8080, reload=True, debug=True) 

    上面代码栗子,请求模型和响应模型都是同一个 Pydantic Model

    FastAPI 通过 response_model 会做

    • 将输出数据转换为 Model 中声明的类型
    • 验证数据
    • 在 OpenAPI 给 Response 添加 JSON Schema 和 Example Value
    • 最重要:将输出数据限制为 model 的数据

    正确传参的请求结果

    查看 Swagger API 文档

    为什么 response_model 不是路径函数参数而是路径操作参数呢?

    • 因为路径函数的返回值并不是固定的,可能是 dict、数据库对象,或其他模型
    • 但是使用响应模型可以对响应数据进行字段限制和序列化

    区分请求模型和响应模型的栗子

    需求

    • 假设一个注册功能
    • 输入账号、密码、昵称、邮箱,注册成功后返回个人信息
    • 正常情况下不应该返回密码,所以请求体和响应体肯定是不一样的

    实际代码

    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
    • 即使请求数据包含了密码,但因为响应模型不包含 password,所以最终返回的响应数据也不会包含 password
    • FastAPI 通过 Pydantic 过滤掉所有未在响应模型中声明的数据

    正确传参的请求结果

    查看 Swagger API 文档

    来看看路径操作有什么关于响应模型的参数

    response_model_exclude_unset

    作用

    • 有时候数据会有默认值,比如数据库中设置了默认值,不想返回这些默认值怎么办?
    •  response_model_exclude_unset=True  设置该参数后就不会返回默认值,只会返回实际设置的值,假设没设置值,则不返回该字段

     

    实际代码

    class Item(BaseModel):
        name: str
        price: float
        # 下面三个字段有默认值
        description: Optional[str] = None
        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):
        # 从上面 items 字典中,根据 item_id 取出对应的值并返回
        return items[item_id]

    item_id=foo 的请求结果

    不会返回有默认值的字段

    item_id=bar 的请求结果

     

    只返回了设置值的字段

    item_id=baz 的请求结果

    • 五个字段都有设置值,所有都包含在响应数据中了
    • 即使 description、tax、tags 设置的值和默认值是一样的,FastAPI 仍然能识别出它们是明确设置的值,所以会包含在响应数据中

    response_model_include、response_model_exclude

    作用

    • include:包含
    • exclude:排除
    • 其实就是响应模型只要包含/排除有些属性

    参数数据类型

    • 从上面可以看到,这两个参数的类型都是 Optional[Union[SetIntStr, DictIntStrAny]] 
    • Optional:可选
    • Union:联合类型
    • 既可以是 SetIntStr,也可以是 DictIntStrAny,满足其一即可

    SetIntStr、DictIntStrAny

    查看源码可以看到

    # set 类型,子元素类型可以是 int、str
    SetIntStr = Set[Union[int, str]]
    
    # dict 类型,键类型可以是 int、str,值类型可以是任意类型
    DictIntStrAny = Dict[Union[int, str], Any]

    官方建议

    • 不推荐使用这两个参数,而推荐使用上面讲到的思想,通过多个类来满足请求模型、响应模型
    • 因为在 OpenAPI 文档中可以看到 Model 完整的 JSON Schema

    response_model_include 的栗子

    结合上面注册功能的栗子:请求要密码,响应不要密码

    class User(BaseModel):
        username: str
        password: str
        email: EmailStr
        full_name: Optional[str] = None
    
    
    @app.post("/user/", response_model=User, response_model_include={"username", "email", "full_name"})
    async def create_user(user: User):
        return user

    正确传参的请求结果

    查看 Swagger API 文档

    passwor 仍然存在,这明显不是我们想要的最佳效果,所以还是推荐用多个类的思想

    response_model_exclude 的栗子

    class User(BaseModel):
        username: str
        password: str
        email: EmailStr
        full_name: Optional[str] = None
    
    
    @app.post("/user/", response_model=User, response_model_exclude={"password"})
    async def create_user(user: User):
        return user

      

    正确传参的请求结果请求结果

    同 include 

    查看 Swagger API 文档

    同 include

  • 相关阅读:
    (一)js概述
    (八)js函数二
    (七)js函数一
    (十)js获取日期
    Java 定时器 Timer 的使用.
    多线程编程学习四(Lock 的使用)
    多线程编程学习三(线程间通信).
    wait/notify 实现多线程交叉备份
    多线程编程学习二(对象及变量的并发访问).
    浅析多线程的对象锁和Class锁
  • 原文地址:https://www.cnblogs.com/poloyy/p/15317585.html
Copyright © 2011-2022 走看看