如何使用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,一经查实,立即删除!

相关文章

springboot/ssm高校疫情防控系统Java校园疫情防控管理平台web

springboot/ssm高校疫情防控系统Java校园疫情防控管理平台web 基于springboot(可改ssm)vue项目 开发语言:Java 框架:springboot/可改ssm vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:…

第三百七十二回

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

LeetCode刷题笔记之二叉树(三)

一、寻找特定节点 1. 404【左叶子之和】 题目: 给定二叉树的根节点 root ,返回所有左叶子之和。代码: class Solution {public int sumOfLeftLeaves(TreeNode root) {//左叶子不止是最左边的叶子,而是二叉树中每个节点的左叶子…

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…

【前端开发】前端开发深度解析:HTML、CSS、JavaScript与Vue.js

一、HTML:构建网页的基石 1.1 简介 HTML(HyperText Markup Language,超文本标记语言)是一种用于创建网页的标准标记语言。它使用各种标签(tags)来描述网页上的内容,包括文本、图像、链接、视频…

类的继承extends以及super

类的继承 继承:基于父类的某个扩展,制定出一个新的子类,而这个子类可以继承父类的原有属性和方法 java是如何体现继承的特性的 平板电脑继承了台式机电脑所拥有的功能(如听音乐)的基础上,同时扩展出自己特殊的用途:如…

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普通用户普通用户:一个主界面,负责展示视频…

【0267】pg内核初始化 process table(ProcGlobal、PROC_HDR、PGPROC)分析

1. 前言 在postmaster或standalone后端启动期间初始化全局进程表(global process table)。该过程由InitProcGlobal()完成,对于此函数: (1)还创建了支持所请求的后端数量所需的所有每个进程信号量。我们过去只在后端真正启动时才分配信号量,但这很糟糕,因为它会让Postg…

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

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

JVM-垃圾回收

一、概念 垃圾回收是JVM的堆中管理内存的一种办法。JVM会在特定条件下回收无用的对象占用的内存空间。 二、判断垃圾的方法 1、引用计数法 这种判断某一对象是否是垃圾的方法的原理是:记录某个对象被引用的次数,如果引用次数是0说明是垃圾。但是有漏…

GameObject类API学习

GameObject类 GameObject类是Unity场景中所有实体的基类。一个GameObject对象通常由多个组件组成,且至少含有一个Transform组件。 1、GameObject类实例属性 在GameObject类中,实例属性有activeSelf和activeInHierarchy。 activeSelf属性:…

Spring与SpringBoot入门

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

Linux内核定时器ioctrl实现对Led灯的控制

一. 简介 前面文章学习了 Linux内核提供的定时器来实现 Led灯的定时亮灭。文章地址如下: Linux内核定时器实现Led灯的定时亮灭说明二-CSDN博客 本文学习通过 应用程序调用 驱动,从而实现对 Led灯的控制。具体实现 ioctrl函数的驱动代码,从而控制 Led灯。 二. Linux内核定…

Unity3D 光照计算方向与法线贴图详解

前言 在Unity3D中&#xff0c;光照计算方向与法线贴图是实现高质量光照效果的重要技术之一。本文将详细介绍光照计算方向与法线贴图的原理和实现方法&#xff0c;并给出相应的代码示例。 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点击进来一起交流…

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

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

Git,GitHub与GitLab分别是什么?有什么关系和区别?

Git 定义&#xff1a;Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;并协助多人协作开发软件项目。作用&#xff1a;Git 可以在本地存储完整的项目历史记录&#xff0c;并允许开发者在不同的分支上进行独立的开发&#xff0c;最后将它们合并到主干分…