【Python开发】FastAPI 03:请求参数—请求体

news2024/11/16 10:41:32

除了路径参数和查询参数,还有请求体,其用于传递 JSON、XML 或其他格式的数据,以便服务器能够读取并做出相应的处理,可以说请求体的作用更为强大。试想一下,如果存在七八个参数,路径参数和查询是不是就招架不住了,但是请求体则可以将这七八个参数一网打尽。

目录

1 声明请求体

1.1 使用 Pydantic 模型

① 创建数据模型

② 声明为参数

③ 请求体 + 路径参数 + 查询参数

④ 数据模型使用 Field

1.2 使用 Body

① 单一值的请求体

② 嵌入单个请求体参数

2 请求体中的嵌套模型

2.1 List 字段

① 未声明元素类型

② 声明元素类型

2.2 Set 类型

2.3 嵌套模型 

2.4 特殊的类型和校验

① HttpUrl

② 纯列表请求体

3 额外数据类型及参数

3.1 其他数据类型

3.2 Cookie 参数

3.3 Header 参数

① 声明 Header 参数

② 自动转换


1 声明请求体

当需要将数据从客户端(例如浏览器)发送给 API(可以理解为是应用后台)时,你将其作为「请求体」发送。

请求体是客户端发送给 API 的数据,响应体是 API 发送给客户端的数据。

你不能使用 GET 操作(HTTP 方法)发送请求体。
要发送请求体,必须使用下列方法之一:POST(较常见)、PUT、DELETE 或 PATCH。

1.1 使用 Pydantic 模型

① 创建数据模型

# 导入 Pydantic 的 BaseModel
from pydantic import BaseModel

#将数据模型声明为继承自 BaseModel 的类,使用标准的 Python 类型来声明所有属性
class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

类似查询参数,某字段若非必须,可为其设置一个默认值或可选 None,否则该字段就是必须的。

上面的模型声明了一个这样的 JSON「object」(或 Python dict):

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

因为 description 和 tax 是可选的(它们的默认值为 None),那么下面的 JSON「object」也是有效的:

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

② 声明为参数

类似路径参数和查询参数,可以使用相同的方式声明请求体,并且将它的类型声明为你创建的 Item 模型,完整代码:

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

@app.post("/items1/")
async def create_item(item: Item):
    return item

此时,我们可以使用交互文档postmanapifox等工具进行请求测试,后边将使用交互文档进行测试。

仅仅使用了 Python 类型声明,FastAPI 将做以下事情:

  • 将请求体作为 JSON 读取。
  • 校验数据。
  • 如果数据无效,将返回一条清晰易读的错误信息,指出不正确数据的确切位置和内容。
  • 将接收的数据赋值到参数 item 中。
  • 这些模式将成为生成的 OpenAPI 模式的一部分,并且被自动化文档 UI 所使用。

在函数内部,你可以直接访问模型对象的所有属性:

...

@app.post("/items2/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict

📌 文档

你所定义模型的 JSON 模式将可以在交互式 API 文档中展示:

③ 请求体 + 路径参数 + 查询参数

你还可以同时声明请求体、路径参数和查询参数。

...

@app.put("/items3/{item_id}")
async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result

请求参数将依次按如下规则进行识别:

  • 如果在路径中也声明了该参数,它将被用作路径参数。
  • 如果参数属于单一类型(比如 int、float、str、bool 等)它将被解释为查询参数。
  • 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体。

④ 数据模型使用 Field

与使用 Query、Path 类似,你可以使用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, Field #导入 Field

app = FastAPI()

class Item1(BaseModel): #对模型属性使用 Field
    name: str
    description: Union[str, None] = Field(
        default=None, title="The description of the item", max_length=300
    )
    price: float = Field(
        gt=0, description="The price must be greater than zero"
    )
    tax: Union[float, None] = None

@app.put("/items4/{item_id}")
async def update_item(item_id: int, item: Item1):
    results = {"item_id": item_id, "item": item}
    return results

Field 的工作方式和 Query 和 Path 相同,包括它们的参数等等也完全相同,详情可以查看上一章内容~

1.2 使用 Body

与使用 Query 和 Path 为查询参数和路径参数定义额外数据的方式相同,FastAPI 提供了一个同等的 Body

① 单一值的请求体

如果该请求参数是一个单一值(比如 strint 等),但是依旧想让他以请求体的形式存在,那么可以使用 Body 来修饰,不然系统将默认他是一个查询参数。

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    username: str
    full_name: Union[str, None] = None

@app.put("/items5/{item_id}")
async def update_item(item_id: int, user: User, single: int = Body()):
    results = {"item_id": item_id, "user": user, "single": single}
    return results

此时,FastAPI 期望的请求体如下:

{
    "user": {
        "username": "yinyu",
        "full_name": "yinyuyu"
    },
    "single": 5
}

② 嵌入单个请求体参数

如果你想要这个 JSON 外再带一个 key,那么可以使用嵌入的特殊 Body 参数:

user: User = Body(embed=True)

比如:

...

@app.put("/items6/{item_id}")
async def update_item(item_id: int, user: User = Body(embed=True)):
    results = {"item_id": item_id, "user": user}
    return results

此时,FastAPI 期望的请求体如下:

{
    "user": {
        "username": "yinyu",
        "full_name": "yinyuyu"
    }
}

而不是:

{
    "username": "yinyu",
    "full_name": "yinyuyu"
}

2 请求体中的嵌套模型

使用 FastAPI,你可以定义、校验、记录文档并使用任意深度嵌套的模型(归功于 Pydantic

2.1 List 字段

① 未声明元素类型

你可以将一个请求体模型的属性/字段定义为拥有子元素的类型。例如 Python list

from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Model1(BaseModel):
    name: str
    price: float
    tags: list = []

@app.put("/model1/{model_id}")
async def update_model(model_id: int, model: Model1):
    results = {"model_id": model_id, "model": model}
    return results

此时,FastAPI 期望的请求体可以如下:

{
  "name": "string",
  "price": 0,
  "tags": [1, "yinyu"]
}

因为 tags 只是一个由元素组成的列表,它没有声明每个元素的类型,因此可以放多个类型的元素进去。

② 声明元素类型

如果我们想指定列表中的元素类型,那么 Python 也提供了一种特定的方法:

要声明具有子类型的类型,例如 listdicttuple

  1. 从 typing 模块导入它们
  2. 使用方括号 [  ] 将子类型作为「类型参数」传入
from typing import List

my_list: List[str]

因此,在我们的示例中,我们可以将 tags 明确地指定为一个「字符串列表」

...

class Model2(BaseModel):
    name: str
    price: float
    tags: List[str] = [] #声明具有子类型的列表,要声明具有子类型的类型,例如 list、dict、tuple:

@app.put("/model2/{model_id}")
async def update_model(model_id: int, model: Model2):
    results = {"model_id": model_id, "model": model}
    return results

2.2 Set 类型

如果你希望列表中的元素不能重复,那么 set 这一数据类型可以很好的满足该要求:

from typing import Set, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Model3(BaseModel):
    name: str
    price: float
    mtags: Set[str] = set()

@app.put("/model3/{model_id}")
async def update_model(model_id: int, model: Model3):
    results = {"model_id": model_id, "model": model}
    return results

此时,FastAPI 期望的请求体可以如下:

{
  "name": "yinyu",
  "price": 0,
  "mtags": ["handsome","handsome"]
}

正确请求后的响应内容则如下:

{
  "model_id": 1,
  "model": {
    "name": "string",
    "price": 0,
    "mtags": ["1"]
  }
}

这样,即使你收到带有重复数据的请求,后台也会将重复元素进行筛选后保留一项。

2.3 嵌套模型 

Pydantic 模型的每个属性/字段都具有类型,那么你可以使得该属性也是一个 Pydantic 模型

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

#定义一个 Image 模型作为子模型
class Image(BaseModel):
    url: str
    name: str

class Base1(BaseModel):
    name: str
    description: Union[str, None] = None
    image: Union[Image, None] = None #将子模型用作类型

@app.put("/base1/{base_id}")
async def update_base(base_id: int, base: Base1):
    results = {"item_id": base_id, "item": base}
    return results

此时,FastAPI 期望的请求体可以如下:

{
    "name": "yinyu",
    "description": "The pretender",
    "image": {
        "url": "http://yinyu.com",
        "name": "The yinyu live"
    }
}

2.4 特殊的类型和校验

① HttpUrl

在 Image 模型中我们有一个 url 字段,我们可以把它声明为 Pydantic 的 HttpUrl,而不是 str,类似的特殊类型可以在 Field Types - Pydantic 页面查看。

from pydantic import BaseModel, HttpUrl

class Image(BaseModel):
    url: HttpUrl
    name: str

② 纯列表请求体

如果你期望的 JSON 请求体的最外层是一个 JSON array(即 Python list),则可以在路径操作函数的参数中声明此类型,就像声明 Pydantic 模型一样:

from typing import List

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()

class Image(BaseModel):
    url: HttpUrl
    name: str

@app.post("/images/multiple/")
async def create_multiple_images(images: List[Image]):
    return images

此时,FastAPI 期望的请求体可以如下 👇,可以有 n 个 Image

[
  {
    "url": "www.11.com",
    "name": "yin"
  },
  {
    "url": "www.22.com",
    "name": "yu"
  }
]

3 额外数据类型及参数

3.1 其他数据类型

Python 同样支持更复杂的数据类型:

  • UUID:
    • 一种标准的 "通用唯一标识符" ,在许多数据库和系统中用作ID。
    • 在请求和响应中将以 str 表示。
  • datetime.datetime:
    • 一个 Python datetime.datetime.
    • 在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 2008-09-15T15:53:00+05:00.
  • datetime.date:
    • Python datetime.date.
    • 在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 2008-09-15.
  • datetime.time:
    • 一个 Python datetime.time.
    • 在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 14:23:55.003.
  • datetime.timedelta:
    • 一个 Python datetime.timedelta.
    • 在请求和响应中将表示为 float 代表总秒数。
    • Pydantic 也允许将其表示为 "ISO 8601 时间差异编码", 查看文档了解更多信息。
  • frozenset:
    • 在请求和响应中,作为 set 对待:
    • 在请求中,列表将被读取,消除重复,并将其转换为一个 set。
    • 在响应中 set 将被转换为 list 。
    • 产生的模式将指定那些 set 的值是唯一的 (使用 JSON 模式的 uniqueItems)。
  • bytes:
    • 标准的 Python bytes。
    • 在请求和相应中被当作 str 处理。
    • 生成的模式将指定这个 str 是 binary "格式"。
  • Decimal:
    • 标准的 Python Decimal。
    • 在请求和相应中被当做 float 一样处理。

比如下面的例子,就使用了上述的一些类型:

@app.put("/items/{item_id}")
async def read_items(
    item_id: UUID,
    start_datetime: Union[datetime, None] = Body(default=None),
    end_datetime: Union[datetime, None] = Body(default=None),
    repeat_at: Union[time, None] = Body(default=None),
    process_after: Union[timedelta, None] = Body(default=None),
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "repeat_at": repeat_at,
        "process_after": process_after,
        "start_process": start_process,
        "duration": duration,
    }

其中函数内的参数有原生的数据类型,可以执行正常的日期操作。

3.2 Cookie 参数

声明 Cookie 参数的结构与声明 Query 参数和 Path 参数时相同,第一个值是参数的默认值,同时也可以传递所有验证参数或注释参数,来对 Cookie 参数进行校验:

from typing import Union

from fastapi import Cookie, FastAPI

app = FastAPI()

@app.get("/items1/")
async def read_items(ads_id: Union[str, None] = Cookie(default=None)):
    return {"ads_id": ads_id}

必须使用 Cookie 来声明 cookie 参数,否则参数将会被解释为查询参数。

3.3 Header 参数

你可以使用定义 QueryPath 和 Cookie 参数一样的方法定义 Header 参数。

① 声明 Header 参数

同样,第一个值是默认值,你可以传递所有的额外验证或注释参数:

from typing import Union

from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/items2/")
async def read_items(user_agent: Union[str, None] = Header(default=None)):
    return {"User-Agent": user_agent}

必须使用 Header 来声明 Header 参数,否则参数将会被解释为查询参数。

② 自动转换

大多数标准的 headers (请求头)用 "连字符" 分隔,比如 user-agent,但是像这样的变量在 Python 中是无效的。因此, 默认情况下, Header 将把参数名称的字符从下划线 (_) 转换为连字符 (-) 来提取并记录 headers

同时,HTTP headers 是大小写不敏感的,你可以像通常在 Python 代码中那样使用 user_agent ,而不需要将首字母大写为 User_Agent 或类似的东西。

如果出于某些原因,你需要禁用下划线到连字符的自动转换,那么可设置 Header 的参数 convert_underscores 为 False:

from typing import Union

from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/items/")
async def read_items(
    strange_header: Union[str, None] = Header(default=None, convert_underscores=False)
):
    return {"strange_header": strange_header}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Camera | 10.linux驱动 led架构-基于rk3568

前面文章我们简单给大家介绍了如何移植闪光灯芯片sgm3141,该驱动依赖了led子系统和v4l2子系统。 V4L2可以参考前面camera系列文章,本文主要讲述led子系统。 一、LED子系统框架 Linux内核的 led 子系统主要功能: 为每个设备在/sys/class/le…

《Linux内核源码分析》(2)进程原理及系统调用

《Linux内核源码分析》(2)进程原理及系统调用 一、进程 操作系统的作用:作为硬件的使用层,提供使用硬件资源的能力, 进程的作用:作为操作系统使用层,提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别&…

【计算机视觉】Segment Anything 安装配置及代码测试(含源代码)

文章目录 一、前言二、安装2.1 基本要求2.2 Install Segment Anything 三、代码使用示例3.1 Automatically generating object masks with SAM3.2 Environment Set-up3.3 显示标注3.4 图像示例3.5 Automatic mask generation3.6 Automatic mask generation options 一、前言 目…

客户体验:响应速度是他们的 No.1 Pick么?

服务响应速度在为消费者提供服务时极为重要,那么,在消费者整体体验中,响应速度是否是消费者最在意的呢? 无论是对企业还是消费者来说,时间都至关重要。消费者在寻求客户服务时,不喜欢等待。根据《客户服务受…

【Python asyncio】零基础也能轻松掌握的学习路线与参考资料

Python asyncio是一个强大而易于使用的库,让Python程序员能够编写高效的异步IO应用程序。它为程序员提供了一种简单而优雅的方法来避免使用 Python GIL(全局解释器锁),同时允许他们轻松地处理高并发的网络通信和并发任务执行。下面…

蓝桥杯数论总结:快速幂和矩阵快速幂

本文先是给出快速幂的原理,又由一道例题明确快速幂的Python代码模版;而后给出矩阵快速幂的原理(介绍了矩阵相乘,对没学过线代者友好),和矩阵快速幂的模版。再给出快速幂和矩阵快速幂相关的题单。 目录 快…

Linux高级---k8s存储

文章目录 一、数据卷的概述二、关系图三、数据卷的类型1、emptydira、描述b、适用场景c、emptydir应用 2、hostpatha、描述b、适用场景c、hostpath应用 3、nfsa、描述b、适用场景c、nfs应用 4、PV和PVCa、描述b、存储卷和存储卷声明的关系c、存储卷声明的管理过程 5、PVa、资源…

10个可以快速用Python进行数据分析的小技巧

一些小提示和小技巧可能是非常有用的,特别是在编程领域。有时候使用一点点黑客技术,既可以节省时间,还可能挽救“生命”。 一个小小的快捷方式或附加组件有时真是天赐之物,并且可以成为真正的生产力助推器。所以,这里…

基于Spring Boot+Vue的课堂管理系统

介绍 基于Spring BootVue的课堂管理系统。前后端分离。包含教师授课管理、学生选退课、聊天室、签到、笔记管理模块等。 技术架构 spring BootMyBatisRedisWebSocketVueCLIAxiosElement UI 项目特点: - 后台使用MyBatis连接数据库,编写后台服务器的…

【教程】2步白嫖使用DeepL Pro会员版 [附插件]

转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 【教程】5步白嫖使用Grammarly Premium高级版 [附脚本] 适用说明 Edge、Chrome等,使用了Chrome内核的浏览器应该都可以吧。 开始白嫖 1、下载并解压插件,下载链接:https://x…

第2章:数据结构【AcWing】

文章目录 单链表定义初始化头插在下标为pos位置后插入删除下标为pos后的结点遍历 双链表定义初始化在下标为pos后插入删除下标为pos的位置 栈和队列栈定义示例代码 队列定义示例代码循环队列定义示例代码 单调栈和单调队列单调栈朴素方法 O ( n 2 ) O(n^2) O(n2)优化 O ( n ) …

Web的基本漏洞--逻辑漏洞

目录 一、逻辑漏洞介绍 1.逻辑漏洞的原理 2.逻辑漏洞的分类 3.常见的逻辑漏洞 4.挖掘逻辑漏洞 一、逻辑漏洞介绍 1.逻辑漏洞的原理 逻辑漏洞是指由于程序逻辑不严或逻辑太复杂,导致一些逻辑分支不能够正常处理或处理错误,从而进行攻击。一般出现任…

英国皇家植物园采用机器学习预测植物抗疟性,将准确率从 0.46 提升至 0.67

内容一览:疟疾是严重危害人类生命健康的重大传染病,研究人员一直在致力于寻找新的植物源性抗疟疾化合物,以研发相关药物。近期英国皇家植物园利用机器学习 算法 有效预测了植物抗疟性,该研究成果目前已发表在《Frontiers in Plant…

路径规划算法:基于风驱动优化的路径规划算法- 附代码

路径规划算法:基于风驱动优化的路径规划算法- 附代码 文章目录 路径规划算法:基于风驱动优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化算法…

游戏场景的转换——状态模式

状态模式 游戏比较复杂时,通常会设计成多个场景。 切换场景的好处 1、重复使用场景 跳转切换场景的代码有两种一种是旧版的方法 Application.LoadLevel(“SampleScene”);另一种是新版的方法 SceneManager.LoadScene(“SampleScene”); 例子1:通过场景…

通过IEDA连接Linux上的MYSQL

一、打开idea新建项目 idea与数据库的连接是与项目强相关的 在项目A中配置的数据库连接a,那么只能在项目A中能看到和使用数据库连接a 二、配置新的数据库连接 1.点击界面左侧栏中的Database,唤出数据库连接界面 2. 新建数据库(mysql&#x…

Linux:apache配置与应用

Linux:apache配置与应用 一、虚拟 Web 主机1.1 虚拟Web主机1.2 httpd服务支持的虚拟主机类型 二、基于域名的虚拟主机2.1 为虚拟主机提供域名解析2.2 为虚拟主机准备网页文档2.3 添加虚拟主机配置2.4 设置访问控制2.5 加载独立的配置文件2.6 在客户机中访问虚拟 Web…

RabbitMQ消息属性详解

content-type属性 如同各种标准化的HTTP规范,content-type传输消息体的MIME类型。例如,如果你的应用程序正在发送JSON序列化的数据值,那么将content-type属性设置为application/json将允许尚待开发的消费者应用程序在收到消息时检查消息类型…

BiFormer实战:使用BiFormer实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译:https://wanghao.blog.csdn.net/article/details/130186102 官方源码:https://github.com/rayleizhu/BiFormer BiFormer是今年提出…

java idea常用的快捷方式

文章目录 java idea常用的快捷方式快速复制选多行改变代码格式化 快速代码编辑psvmsout5.for java idea常用的快捷方式 快速复制 c t r l d \color{red}{ctrld} ctrld 选多行改变 A l t 鼠标 \color{red}{Alt鼠标} Alt鼠标 代码格式化 C t r l A l t l \color{red}{Ctrl…