如何使用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.mzph.cn/news/707574.shtml

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

相关文章

第三百七十二回

文章目录 1. 概念介绍2. 实现方法2.1 maskFilter2.2 shader 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"两种阴影效果"相关的内容,本章回中将介绍如何绘制阴影效果.闲话休提,让我们一起Talk Flutter吧。 1. 概…

java多线程并发实战,java高并发场景面试题

阶段一:筑基 Java基础掌握不牢,对于一个开发人员来说无疑是非常致命的。学习任何一个技术知识无疑不是从基础开始;在面试的时候,面试官无疑不是从基础开始拷问。 内容包括:Java概述、Java基本语法、Java 执行控制流程、…

html5盒子模型

1.边框的常用属性 border-color 属性 说明 示例 border-top-color 上边框颜色 border-top-color:#369; border-right-color 右边框颜色 border-right-color:#369; border-bottom-color 下边框颜色 border-bottom-color:#fae45b; border-left-color 左边框颜色…

java springmvc/springboot 项目通过HttpServletRequest对象获取请求体body工具类

请求 测试接口 获取到的 获取到打印出的json字符串里有空格这些,在json解析的时候正常解析为json对象了。 工具类代码 import lombok.extern.slf4j.Slf4j; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.we…

pikachu之xss获取键盘记录

前备知识 跨域 跨域(Cross-Origin)是指在互联网中,浏览器为了保护用户信息安全而实施的一种安全策略——同源策略(Same-Origin Policy),即浏览器禁止一个域上的文档或者脚本(如通过JavaScript发…

从零开始学习Netty - 学习笔记 -Netty入门-ChannelFuture

5.2.2.Channel Channel 的基本概念 在 Netty 中,Channel 是表示网络传输的开放连接的抽象。它提供了对不同种类网络传输的统一视图,比如 TCP 和 UDP。 Channel 的生命周期 Channel 的生命周期包括创建、激活、连接、读取、写入和关闭等阶段。Netty 中…

QT C++实战:实现用户登录页面及多个界面跳转

主要思路 一个登录界面,以管理员Or普通用户登录管理员:一个管理员的操作界面,可以把数据录入到数据库中。有返回登陆按钮,可以选择重新登陆(管理员Or普通用户普通用户:一个主界面,负责展示视频…

vue组件中data为什么必须是一个函数

查看本专栏目录 关于作者 还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas&#x…

Spring与SpringBoot入门

Spring入门 要使用Spring最起码需要引入两个依赖: <!-- Spring Core&#xff08;核心&#xff09; --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.20</version>…

密码学系列(四)——对称密码2

一、RC4 RC4&#xff08;Rivest Cipher 4&#xff09;是一种对称流密码算法&#xff0c;由Ron Rivest于1987年设计。它以其简单性和高速性而闻名&#xff0c;并广泛应用于网络通信和安全协议中。下面是对RC4的详细介绍&#xff1a; 密钥长度&#xff1a; RC4的密钥长度可变&am…

GPT 的基础 - T(Transformer)

我们知道GPT的含义是&#xff1a; Generative - 生成下一个词 Pre-trained - 文本预训练 Transformer - 基于Transformer架构 我们看到Transformer模型是GPT的基础&#xff0c;这篇博客梳理了一下Transformer的知识点。 BERT: 用于语言理解。&#xff08;Transformer的Encoder…

九州金榜|父亲在教育中的作用及重要性

随着社会进步&#xff0c;对比以前教育&#xff0c;现在父亲在教育中的作用越来越明显&#xff0c;孩子的教育离不开父亲&#xff0c;父亲在孩子教育中有什么作用&#xff1f;重要性又是什么呢&#xff1f;下面九州金榜家庭教育就带大家一起分析一下作为父亲&#xff0c;在孩子…

VUE3搭载到服务器

1.搭建服务器 使用 Windows 自带的 IIS 作为服务器。 步骤如下&#xff1a;https://blog.csdn.net/qq_62464995/article/details/130140673 同时&#xff0c;上面的步骤中&#xff0c;还使用了 cpolar 将 IIS 本地网址映射到公共网址。 注&#xff1a; cpolar客户端&#xf…

Ant for Blazor做单个表的增删查改

Ant for Blazor做单个表的增删查改 2024年02月27日花了一天时间弄出来了&#xff0c;基本弄好了&#xff0c;vs2022blazor servernet8,引用的AntDesign版本是0.17.4 代码里的model和repository是用自己牛腩代码生成器生成的东西&#xff0c;sqlsugar的&#xff0c;记得在prog…

括号生成(力扣题目22)

题目描述&#xff1a; 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()&q…

Modern C++ std::any的实现原理

1. 前言 std::any 是 C17 中引入的一个新特性&#xff0c;它是一个类型安全的容器&#xff0c;可以在其中存储任何类型(但此类型必须可拷贝构造)的值&#xff0c;包括基本类型、自定义类型、指针等。相比于void* 指针&#xff0c;std::any 更为类型安全&#xff0c;可以避免由…

NC65 rest接口 开发 NC65接口开发

一、在对应模块META-INF下编写 xxx.rest 文件,也要放在Home里对应的目录下。 二、开发接口&#xff0c;继承extends AbstractUAPRestResource&#xff0c;&#xff08;有的项目会继承别的方法如&#xff1a;AbstractNCCRestResource&#xff0c;MTFRestResource&#xff1b;有…

使用 kubeadm 部署k8s集群

一、所有节点系统初始化 1、常规初始化 2、内核版本升级以及内核限制文件参数修改 还可以考虑将旧版本的内核卸载 二、准备nginx负载均衡器和keepalived nginx四层代理&#xff1a; keepalived配置&#xff1a; nginx检测脚本&#xff1a; 三、所有节点部署docker&#xff0c…

SQL函数学习记录

聚合函数 函数是编程语言的基础之一&#xff0c;在对数字的运算中&#xff0c;我们用的最多的就是聚合函数&#xff0c;本篇接下来就详细阐述下SQL中聚合函数的运用。 什么是聚合函数&#xff08;aggregate function&#xff09;&#xff1f; 聚合函数指的是对一组值执行计算…

2023秋季飞书未来无限大会--随笔

这个时代的飞书 数字时代 工作协同平台 AI时代 帮助企业和个人用好AI 企业如何引用大模型能力&#xff1f; 智慧体— 接近人&#xff0c;有进步空间智能伙伴 用时代的科技打造爱不释手的好产品 移动互联网 – 改变信息分发方式 大模型 –自然的人机交互方式 业务协同 …