如何使用Fastapi上传文件?先从请求体数据讲起

文章目录

  • 1、请求体数据
  • 2、form表单数据
  • 3、小文件上传
    • 1.单文件上传
    • 2.多文件上传
  • 4、大文件上传
    • 1.单文件上传
    • 2.多文件上传

1、请求体数据

前面我们讲到,get请求中,我们将请求数据放在url中,其实是非常不安全的,我们更愿意将请求数据放在请求体中。
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。

FastAPI 基于 Pydantic ,Pydantic 主要用来做类型强制检查(校验数据)。不符合类型要求就会抛出异常。

对于 API 服务,支持类型检查非常有用,会让服务更加健壮,也会加快开发速度,因为开发者再也不用自己写一行一行的做类型检查。

安装上手
pip install pydantic

from fastapi import FastAPI  # FastAPI 是一个为你的 API 提供了所有功能的 Python 类。
import uvicornfrom typing import Optional,Union,Listfrom pydantic import BaseModel,Fieldfrom datetime import date#创建应用程序,app是应用程序名
app = FastAPI()  # 这个实例将是创建你所有 API 的主要交互对象。这个 app 同样在如下命令中被 uvicorn 所引用#fastapi要实现校验功能,需要借助pydantic这个模块,我们需要自己写个类,继承pydantic模块中的BaseModel,才能具有该功能
#在类型上做类型限制
class User(BaseModel):name:str = 'root'#默认是0,输入限制大于0,小于100age: int = Field(default=0, lt=100, gt=0)birth: Optional[date] = None#限制为数组,里面的元素限制为int类型friends: List[int] = []description: Union[str, None] = None#异步的请求参数,函数加上async
@app.post("/data") #路径参数与查询参数共存
#传参data限制为User类型
async def data(data:User):#将查询结果返回return {}if __name__ == '__main__':#注意,run的第一个参数 必须是文件名:应用程序名uvicorn.run("请求体数据:app", port=8080,  reload=True)

在docs测试,可以看到请求体限制数据类型
在这里插入图片描述

报错排查
在这里插入图片描述

报错:

TypeError: Failed to execute ‘fetch’ on ‘Window’: Request with GET/HEAD method cannot have body.

有@ResponseBody才会在接口中获取swagger列表

是由于方法中申明的是get方法却用了@requestBody

故将get 请求改为post 请求即可

当传参不符合限制要求,响应失败,提示年龄应小于100
在这里插入图片描述

当请求体参数完全符合要求,才能正确响应
在这里插入图片描述

我们可以将数据返回
#fastapi要实现校验功能,需要借助pydantic这个模块,我们需要自己写个类,继承pydantic模块中的BaseModel,才能具有该功能

#在类型上做类型限制
class User(BaseModel):name:str = 'root'#默认是0,输入限制大于0,小于100age: int = Field(default=0, lt=100, gt=0)birth: Optional[date] = None#限制为数组,里面的元素限制为int类型friends: List[int] = []description: Union[str, None] = None#异步的请求参数,函数加上async
@app.post("/data") #路径参数与查询参数共存
#将传参data限制为User类型
async def data(data:User):print(data,type(data))#将查询结果返回return data

在这里插入图片描述

注意,当输入的数据类型跟限制类型不一致时,pydantic会尝试做数据类型转换,转换成功就可以正常返回,转换失败才报错

Field比较强大,可以做各种限制,甚至可以做正则限制 pattern

def Field(  # noqa: C901default: Any = PydanticUndefined,*,default_factory: typing.Callable[[], Any] | None = _Unset,alias: str | None = _Unset,alias_priority: int | None = _Unset,validation_alias: str | AliasPath | AliasChoices | None = _Unset,serialization_alias: str | None = _Unset,title: str | None = _Unset,description: str | None = _Unset,examples: list[Any] | None = _Unset,exclude: bool | None = _Unset,discriminator: str | types.Discriminator | None = _Unset,json_schema_extra: JsonDict | typing.Callable[[JsonDict], None] | None = _Unset,frozen: bool | None = _Unset,validate_default: bool | None = _Unset,repr: bool = _Unset,init: bool | None = _Unset,init_var: bool | None = _Unset,kw_only: bool | None = _Unset,pattern: str | None = _Unset,strict: bool | None = _Unset,gt: float | None = _Unset,ge: float | None = _Unset,lt: float | None = _Unset,le: float | None = _Unset,multiple_of: float | None = _Unset,allow_inf_nan: bool | None = _Unset,max_digits: int | None = _Unset,decimal_places: int | None = _Unset,min_length: int | None = _Unset,max_length: int | None = _Unset,union_mode: Literal['smart', 'left_to_right'] = _Unset,**extra: Unpack[_EmptyKwargs],

也可以自定义一个函数做限制,使用到了pydantic里面的validator装饰器
最新版的validator已被废弃
在这里插入图片描述

最新版使用field_validator装饰器

#在类型上做类型限制
class User(BaseModel):name:str = 'root'#默认是0,输入限制大于0,小于100age: int = Field(default=0, lt=100, gt=0)birth: Optional[date] = None#限制为数组,里面的元素限制为int类型friends: List[int] = []description: Union[str, None] = None@field_validator('name')def validate_name(cls,v):assert v.isalpha(), 'name must be alpha'return v

校验生效
在这里插入图片描述

类型嵌套:
我们定义的类型,可以组合嵌套方式使用
在这里插入图片描述
在这里插入图片描述

class Data(BaseModel): # 类型嵌套
users: List[User]

@app.post(“/data/”)
async def create_data(data: Data):
# 添加数据库
return data

也可以这样嵌套,请求体数据是列表套字典形式

2、form表单数据

在 OAuth2 规范的一种使用方式(密码流)中,需要将用户名、密码作为表单字段发送,而不是 JSON。

FastAPI 可以使用Form组件来接收表单数据,需要先使用 pip install python-multipart 命令进行安装。
pip install python-multipart
在这里插入图片描述

from fastapi import FastAPI, Form
import uvicornapp = FastAPI()@app.post("/regin")
def regin(username: str = Form(..., max_length=16, min_length=8, pattern='[a-zA-Z]'),   #Form对输入的数据可以做些限制password: str = Form(..., max_length=16, min_length=8, pattern='[0-9]')):print(f"username:{username},password:{password}")return {"username": username}if __name__ == '__main__':#注意,run的第一个参数 必须是文件名:应用程序名uvicorn.run("表单:app", port=8080,  reload=True)

在这里插入图片描述

此时发送请求,content-type 必须是application/x-www-form-urlencoded
否则发送请求失败
在这里插入图片描述

使用application/x-www-form-urlencoded发送成功
在这里插入图片描述

3、小文件上传

文件上传,文件会放在请求体里面,但是请求头的content-type是multipart/form-data

1.单文件上传

# file: bytes = File():适合小文件上传
@app.post("/files/")
#文件时字节流类型,是fastapi里面的File类型
async def create_file(file: bytes = File()):print("file:", file)return {"file_size": len(file)}

在docs请求测试,可以看到请求的content-type是multipart/form-data
返回了图片的字节流长度
在这里插入图片描述

看下后台打印
在这里插入图片描述

但是这样上传只适合小文件,因为上传的文件会占用用户内存,太大的话会把内存撑爆

2.多文件上传

#多文件上传
@app.post("/multiFiles/")
async def create_files(files: List[bytes] = File()):for file in files:print(len(file))return {"file_sizes": [len(file) for file in files]}

点一次Add string item,就会增加一个文件上传按钮
在这里插入图片描述

看下后台打印
在这里插入图片描述

4、大文件上传

文件比较大时,如果一次性上传,可能会把用户内存撑爆,因此比较常见的处理方式就是分批上传。
上传大文件使用fastapi的UploadFile

1.单文件上传

from fastapi import FastAPI, File, UploadFile# file: UploadFile:适合大文件上传,比较常用@app.post("/uploadFile/")
#直接对应UploadFile类型数据
async def create_upload_file(file: UploadFile):#打印文件名称print('file',file.filename)#将上传的文件保存到服务本地with open(f"{file.filename}", 'wb') as f:#一次读取1024字节,循环读取写入for chunk in iter(lambda: file.file.read(1024), b''):f.write(chunk)return {"filename": file.filename}

在这里插入图片描述

后台打印
在这里插入图片描述

可以看到上传的文件被保存在服务端本地
在这里插入图片描述

单文件上传完整代码:

from fastapi import FastAPI, File, UploadFile
from typing import List
import uvicornapp = FastAPI()# file: UploadFile:适合大文件上传,比较常用@app.post("/uploadFile/")
#直接对应UploadFile类型数据
async def create_upload_file(file: UploadFile):#打印文件名称print('file',file.filename)#将上传的文件保存到服务本地with open(f"{file.filename}", 'wb') as f:#一次读取1024字节,循环读取写入for chunk in iter(lambda: file.file.read(1024), b''):f.write(chunk)return {"filename": file.filename}if __name__ == '__main__':#注意,run的第一个参数 必须是文件名:应用程序名uvicorn.run("文件上传:app", port=8080,  reload=True)

2.多文件上传

#上传多个文件
@app.post("/multiUploadFiles/")
async def create_upload_files(files: List[UploadFile]):for file in files:print(file.filename)# 将上传的文件保存到服务本地path = os.path.join('images',f'{file.filename}')with open(path, 'wb') as f:# 一次读取1024字节,循环读取写入for chunk in iter(lambda: file.file.read(1024), b''):f.write(chunk)return {"filenames": [file.filename for file in files]}

在这里插入图片描述

看下后台打印,以及上传的文件
在这里插入图片描述

查看下载的文件
在这里插入图片描述

多文件上传代码:

from fastapi import FastAPI, File, UploadFile
from typing import List
import uvicorn
import osapp = FastAPI()#上传多个文件
@app.post("/multiUploadFiles/")
async def create_upload_files(files: List[UploadFile]):for file in files:print(file.filename)# 将上传的文件保存到服务本地path = os.path.join('images',f'{file.filename}')with open(path, 'wb') as f:# 一次读取1024字节,循环读取写入for chunk in iter(lambda: file.file.read(1024), b''):f.write(chunk)return {"filenames": [file.filename for file in files]}if __name__ == '__main__':#注意,run的第一个参数 必须是文件名:应用程序名uvicorn.run("文件上传:app", port=8080,  reload=True)

怎么样小伙伴,使用fastapi实现文件上传是不是很简单,有兴趣抓紧试试吧!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QML | JavaScript函数[自定义方法\导入JavaScript文件中的函数\关联信号和JavaScript 函数]

1、JavaScript函数 在前面的方法特性一节中已经讲解了函数的使用,这里再从JavaScript的角度讲解一些需要注意的方面。程序逻辑可以在JavaScript函数中进行定义。这些函数可以定义在QML文档里面(例如前面讲到的自定义方法),也可以定义在外部导人的JavaScript文件中。 (1)自…

拒绝机械风,让ChatGPT像真人一样对话!

拒绝机械风,让ChatGPT像真人一样对话 在这个信息爆炸的时代,人工智能技术的快速发展让我们的生活变得更加便捷。 特别是在自然语言处理领域,ChatGPT的出现无疑是一次革命性的进步。 然而,虽然ChatGPT在很多方面表现出了惊人的能…

学习笔记-李沐动手学深度学习(七)(19-21,卷积层、填充padding、步幅stride、多输入多输出通道)

总结 19-卷积层 【补充】看评论区建议的卷积动画视频 数学中的卷积 【链接】https://www.bilibili.com/video/BV1VV411478E/?fromsearch&seid1725700777641154181&vd_sourcee81e116c4ffe5e79d4bc44738263eda4 【可判断是否为卷积的典型标志】两个函数中自变量相加…

【HarmonyOS】鸿蒙开发之Video组件——第3.7章

Video组件内VideoOptions属性简介 src:设置视频地址。currentProgressRate:设置视频播放倍速,参数说明如下: number|string:只支持 0.75 , 1.0 , 1.25 , 1.75 , 2.0 。P…

vue-router4 (六) 命名视图

命名视图可以使得同一级(同一个组件)中展示更多的路由视图,而不是嵌套显示, 命名视图可以让一个组件中具有多个路由渲染出口,这对于一些特定的布局组件非常有用。 应用场景: 比如点击login切换到组件A&am…

安装 docker 可视化工具 portainer

portainer 官方网站 https://www.portainer.io/ 一、portainer 介绍 Portainer是一款开源的容器管理平台,它提供了一个直观易用的Web界面,帮助用户管理Docker容器集群、镜像、卷等资源。Portainer 支持多种 Docker 环境,包括本地Docker、Sw…

数据库之MVCC

1、什么是MVCC MVCC(Multi-Version Concurrency Control)即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。MVCC使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行…

线性表——单链表的增删查改

本节复习链表的增删查改 首先, 链表不是连续的, 而是通过指针联系起来的。 如图: 这四个节点不是连续的内存空间, 但是彼此之间使用了一个指针来连接。 这就是链表。 现在我们来实现链表的增删查改。 目录 单链表的全部接口…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的水果识别系统(Python+PySide6界面+训练代码)

摘要:本篇博客详尽介绍了一套基于深度学习的水果识别系统及其实现代码。系统采用了尖端的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等前代算法进行了详细的性能对比分析,提供在识别图像、视频、实时视频流和批量文件中水果方面的高效准确性。文…

Rocky Linux 运维工具 mv

一、mv的简介 ​​mv​是Linux系统中的命令,用于移动文件或重命名文件。它可以在同一文件系统内将文件从一个目录移动到另一个目录,也可以修改文件的名称。 二、mv的参数说明 1、 三、mv的实战示例 1、重命名 ###查看目录/root/下的文件列表 [rootloc…

selenium-激活pycharm,以及在pycharm中使用selenium时标红报错问题处理

激活pycharm:http://idea.955code.com/ 01 pycharm中导入selenium报错 现象: pycharm中输入from selenium import webdriver, selenium标红 原因1: pycharm使用的虚拟环境中没有安装selenium: 解决方法: 在pycharm中通过设置或terminal面板重新安装s…

代码随想录算法训练营第三十六天|背包理论基础,416. 分割等和子集

系列文章目录 代码随想录算法训练营第一天|数组理论基础,704. 二分查找,27. 移除元素 代码随想录算法训练营第二天|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II 代码随想录算法训练营第三天|链表理论基础&#xff…