三周精通FastAPI:15 请求文件和同时请求表单+文件

官网文档:请求文件 - FastAPI

请求文件¶

File 用于定义客户端的上传文件。

from fastapi import FastAPI, File, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: bytes = File()):return {"file_size": len(file)}@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):return {"filename": file.filename}

"说明"

因为上传文件以「表单数据」形式发送。

所以接收上传文件,要预先安装 python-multipart。

例如: pip install python-multipart

导入 File

从 fastapi 导入 File 和 UploadFile

from fastapi import FastAPI, File, UploadFile

定义 File 参数¶

创建文件(File)参数的方式与 Body 和 Form 一样:

@app.post("/files/")
async def create_file(file: bytes = File()):return {"file_size": len(file)}

"说明"

File 是直接继承自 Form 的类。

注意,从 fastapi 导入的 QueryPathFile 等项,实际上是返回特定类的函数。

"提示"

声明文件体必须使用 File,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。

文件作为「表单数据」上传。

如果把路径操作函数参数的类型声明为 bytesFastAPI 将以 bytes 形式读取和接收文件内容。

这种方式把文件的所有内容都存储在内存里,适用于小型文件。

不过,很多情况下,UploadFile 更好用。

含 UploadFile 的文件参数¶

定义文件参数时使用 UploadFile

from fastapi import FastAPI, File, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: bytes = File()):return {"file_size": len(file)}@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):return {"filename": file.filename}

UploadFile 与 bytes 相比有更多优势:

  • 使用 spooled 文件:
    • 存储在内存的文件超出最大上限时,FastAPI 会把文件存入磁盘;
  • 这种方式更适于处理图像、视频、二进制文件等大型文件,好处是不会占用所有内存;
  • 可获取上传文件的元数据;
  • 自带 file-like async 接口;
  • 暴露的 Python SpooledTemporaryFile 对象,可直接传递给其他预期「file-like」对象的库。

UploadFile

UploadFile 的属性如下:

  • filename:上传文件名字符串(str),例如, myimage.jpg
  • content_type:内容类型(MIME 类型 / 媒体类型)字符串(str),例如,image/jpeg
  • file: SpooledTemporaryFile( file-like 对象)。其实就是 Python文件,可直接传递给其他预期 file-like 对象的函数或支持库。

UploadFile 支持以下 async 方法,(使用内部 SpooledTemporaryFile)可调用相应的文件方法。

  • write(data):把 data (str 或 bytes)写入文件;
  • read(size):按指定数量的字节或字符(size (int))读取文件内容;
  • seek(offset):移动至文件 offset (int)字节处的位置;
    • 例如,await myfile.seek(0) 移动到文件开头;
    • 执行 await myfile.read() 后,需再次读取已读取内容时,这种方法特别好用;
  • close():关闭文件。

因为上述方法都是 async 方法,要搭配「await」使用。

例如,在 async 路径操作函数 内,要用以下方式读取文件内容:

contents = await myfile.read()

在普通 def 路径操作函数 内,则可以直接访问 UploadFile.file,例如:

contents = myfile.file.read()

"async 技术细节"

使用 async 方法时,FastAPI 在线程池中执行文件方法,并 await 操作完成。

"Starlette 技术细节"

FastAPI 的 UploadFile 直接继承自 Starlette 的 UploadFile,但添加了一些必要功能,使之与 Pydantic 及 FastAPI 的其它部件兼容。

什么是 「表单数据」¶

与 JSON 不同,HTML 表单(<form></form>)向服务器发送数据通常使用「特殊」的编码。

FastAPI 要确保从正确的位置读取数据,而不是读取 JSON。

"技术细节"

不包含文件时,表单数据一般用 application/x-www-form-urlencoded「媒体类型」编码。

但表单包含文件时,编码为 multipart/form-data。使用了 FileFastAPI 就知道要从请求体的正确位置获取文件。

编码和表单字段详见 MDN Web 文档的 POST  小节。

"警告"

可在一个路径操作中声明多个 File 和 Form 参数,但不能同时声明要接收 JSON 的 Body 字段。因为此时请求体的编码是 multipart/form-data,不是 application/json

这不是 FastAPI 的问题,而是 HTTP 协议的规定。

可选文件上传¶

您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选:

from fastapi import FastAPI, File, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: bytes | None = File(default=None)):if not file:return {"message": "No file sent"}else:return {"file_size": len(file)}@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):if not file:return {"message": "No upload file sent"}else:return {"filename": file.filename}

带有额外元数据的 UploadFile

您也可以将 File() 与 UploadFile 一起使用,例如,设置额外的元数据:

from fastapi import FastAPI, File, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: bytes = File(description="A file read as bytes")):return {"file_size": len(file)}@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(description="A file read as UploadFile"),
):return {"filename": file.filename}

多文件上传¶

FastAPI 支持同时上传多个文件。

可用同一个「表单字段」发送含多个文件的「表单数据」。上传多个文件时,要声明含 bytes 或 UploadFile 的列表(List):

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponseapp = FastAPI()@app.post("/files/")
async def create_files(files: list[bytes] = File()):return {"file_sizes": [len(file) for file in files]}@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):return {"filenames": [file.filename for file in files]}@app.get("/")
async def main():content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>"""return HTMLResponse(content=content)

接收的也是含 bytes 或 UploadFile 的列表(list)。

"技术细节"

也可以使用 from starlette.responses import HTMLResponse

fastapi.responses 其实与 starlette.responses 相同,只是为了方便开发者调用。实际上,大多数 FastAPI 的响应都直接从 Starlette 调用。

带有额外元数据的多文件上传¶

和之前的方式一样, 您可以为 File() 设置额外参数, 即使是 UploadFile:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponseapp = FastAPI()@app.post("/files/")
async def create_files(files: list[bytes] = File(description="Multiple files as bytes"),
):return {"file_sizes": [len(file) for file in files]}@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile] = File(description="Multiple files as UploadFile"),
):return {"filenames": [file.filename for file in files]}@app.get("/")
async def main():content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>"""return HTMLResponse(content=content)

小结¶

本节介绍了如何用 File 把上传文件声明为(表单数据的)输入参数。

请求表单与文件¶

FastAPI 支持同时使用 File 和 Form 定义文件和表单字段。

from typing import Annotatedfrom fastapi import FastAPI, File, Form, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: Annotated[bytes, File()],fileb: Annotated[UploadFile, File()],token: Annotated[str, Form()],
):return {"file_size": len(file),"token": token,"fileb_content_type": fileb.content_type,}

 这段代码中文版和英文版不一样,这里用了英文版的。

"说明"

接收上传文件或表单数据,要预先安装 python-multipart。

例如,pip install python-multipart

导入 File 与 Form

 
from fastapi import FastAPI, File, Form, UploadFile

定义 File 与 Form 参数¶

创建文件和表单参数的方式与 Body 和 Query 一样:

@app.post("/files/")
async def create_file(file: Annotated[bytes, File()],fileb: Annotated[UploadFile, File()],token: Annotated[str, Form()],
):

文件和表单字段作为表单数据上传与接收。

声明文件可以使用 bytes 或 UploadFile 。

"警告"

可在一个路径操作中声明多个 File 与 Form 参数,但不能同时声明要接收 JSON 的 Body 字段。因为此时请求体的编码为 multipart/form-data,不是 application/json

这不是 FastAPI 的问题,而是 HTTP 协议的规定。

小结¶

在同一个请求中接收数据和文件时,应同时使用 File 和 Form

实践

请求文件

源代码

源代码写入upload.py文件:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponseapp = FastAPI()@app.post("/files/")
async def create_files(files: list[bytes] = File()):return {"file_sizes": [len(file) for file in files]}@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):return {"filenames": [file.filename for file in files]}@app.get("/")
async def main():content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>"""return HTMLResponse(content=content)

启动服务

uvicorn upload:app --reload

curl测试单个文件上传

先准备好待上传的文件放到合适的地方,然后执行curl命令:

curl -F "files=@/Users/skywalk/work/demo.txt;type=application/octet-stream" http://127.0.0.1:8000/files/

输出:

{"file_sizes":[56]}

证明这个demo.txt文件确实上传成功了!

要注意,文件等号后面需要带“@”标记,否则会报错:

    tg.start_soon(process_fn, sub_value.read)

                              ^^^^^^^^^^^^^^

AttributeError: 'str' object has no attribute 'read'

curl测试多个文件上传

准备好2个待上传的文件放到合适的地方,

curl请求两个文件:

curl -F "files=@/Users/skywalk/work/demo.txt;type=application/octet-stream" -F "files=@/Users/skywalk/work/demo1.txt;type=application/octet-stream" http://127.0.0.1:8000/files/

输出:

{"file_sizes":[56,56]} 

当然用uploadfile链接也是可以的:

curl -F "files=@/Users/skywalk/work/demo.txt;type=application/octet-stream" -F "files=@/Users/skywalk/work/demo1.txt;type=application/octet-stream" http://127.0.0.1:8000/uploadfiles/

输出:{"filenames":["demo.txt","demo1.txt"]} 

请求表单和文件

源代码

保存代码到uploadform.py文件:

from typing import Annotatedfrom fastapi import FastAPI, File, Form, UploadFileapp = FastAPI()@app.post("/files/")
async def create_file(file: Annotated[bytes, File()],fileb: Annotated[UploadFile, File()],token: Annotated[str, Form()],
):return {"file_size": len(file),"token": token,"fileb_content_type": fileb.content_type,"fileb_name":fileb.filename,}

启动服务

uvicorn uploadform:app --reload

curl测试

curl -F "file=@/Users/skywalk/work/demo.txt"  -F "fileb=@//Users/skywalk/work/demo1.txt;type=application/octet-stream" -F "token=your_security_token" http://127.0.0.1:8000/files/

输出结果:

curl -F "file=@/Users/skywalk/work/demo.txt"  -F "fileb=@//Users/skywalk/work/demo1.txt;type=application/octet-stream" -F "token=your_security_token" http://127.0.0.1:8000/files/
{"file_size":56,"token":"your_security_token","fileb_content_type":"application/octet-stream","fileb_name":"demo1.txt"}

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

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

相关文章

直播系统源码技术搭建部署流程及配置步骤

系统环境要求 PHP版本&#xff1a;5.6、7.3 Mysql版本&#xff1a;5.6&#xff0c;5.7需要关闭严格模式 Nginx&#xff1a;任何版本 Redis&#xff1a;需要给所有PHP版本安装Redis扩展&#xff0c;不需要设置Redis密码 最好使用面板安装&#xff1a;宝塔面板 - 简单好用的…

Kafka消费者故障,出现活锁问题如何解决?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka消费者故障&#xff0c;出现活锁问题如何解决&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; Kafka消费者故障&#xff0c;出现活锁问题如何解决&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资…

【C++】string类 (模拟实现详解 下)

我们接着上一篇【C】string类 &#xff08;模拟实现详解 上&#xff09;-CSDN博客继续对string模拟实现。从这篇内容开始&#xff0c;string相关函数的实现就要声明和定义分离了。 1.reserve、push_back和append 在string.h的string类里进行函数的声明。 void reserve(size_…

Maven项目报错:invalid LOC header (bad signature)

文章目录 Maven项目报错&#xff1a;invalid LOC header (bad signature)1. Maven项目加载或Pom.Xml刷新后仍出现如下错误2. 解决方法 Maven项目报错&#xff1a;invalid LOC header (bad signature) 1. Maven项目加载或Pom.Xml刷新后仍出现如下错误 错误提示&#xff1a; in…

【Spring MVC】请求参数的获取

我的主页 1. 获取 URL 中的参数 获取 URL 中的参数是通过 PathVariable 注解实现的 RequestMapping("/article/{articleId}") public String method12(PathVariable("articleId") String articleId){return "接收到参数articleId: " articleI…

书生第四期作业:L0G4000 任务作业

模型下载 在github-codespace 登录codespace安装依赖&#xff1a; 运行下载的py文件&#xff0c;下载模型配置文件&#xff0c; 下载完成 在intern-studio开发机 下载配置文件 下载完成

2024系统架构师---真题考试知识点

1.逻辑地址的构成是“逻辑地址&页内地址”&#xff0c;而物理地址的构成“物理块号&页内地址”&#xff0c;因此只要找出逻辑地址中那几位表示逻辑页号基本就完成了。页内大小4k4*2的10次方2的12次方&#xff0c;可以得出页内地址占12位&#xff0c;因此1B1AH的后12位&…

群控系统服务端开发模式-系统架构图

一、开发服务(1.0版本)&#xff1a; 平台前端服务、平台api接口服务、国外api处理服务&#xff1b; 二、开发服务(2.0版本)&#xff1a; 国内客户端前端服务、国内客户端api接口服务、国外客户端前端服务、国外客户端api接口服务&#xff1b; 三、运行服务(1.0版本)&#xff…

JavaWeb合集22-Apache POI

二十二、Apache POI Apache POI是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用POI在Java 序中对Miscrosoft Office各种文件进行读写操作。一般情况下&#xff0c;POI都是用于操作Excel文件。 使用场景&#xff1a;银行网银系统导出…

【Android】Kotlin教程(2)

文章目录 1.空安全2.let安全调用3.非空断言操作符!!4.空合并操作符 ?:5.异常6.先决条件函数7.substring8.split函数9.replace10.字符串比较11.安全转换函数12.标准库函数1.apply2.run3.with4.also5.takeIf6.takeUnless 1.空安全 为了避免NullPointerException&#xff0c;Kot…

【2024|滑坡数据集论文解读3】CAS滑坡数据集:用于深度学习滑坡检测的大规模多传感器数据集

【2024|滑坡数据集论文解读3】CAS滑坡数据集&#xff1a;用于深度学习滑坡检测的大规模多传感器数据集 【2024|滑坡数据集论文解读3】CAS滑坡数据集&#xff1a;用于深度学习滑坡检测的大规模多传感器数据集 文章目录 【2024|滑坡数据集论文解读3】CAS滑坡数据集&#xff1a;用…

计算机网络(十二) —— 高级IO

#1024程序员节 | 征文# 目录 一&#xff0c;预备 1.1 重新理解IO 1.2 五种IO模型 1.3 非阻塞IO 二&#xff0c;select 2.1 关于select 2.2 select接口参数解释 2.3 timeval结构体和fd_set类型 2.4 socket就绪条件 2.5 select基本工作流程 2.6 简单select的服务器代…

c++编解码封装

多态版编解码 对服务器和客户端的结构体进行序列化然后对数据进行反序列化 案例分析 代码demo Codec.h #pragma once #include <iostream>class Codec { public:Codec();virtual std::string encodeMsg();//string是标准库的string类virtual void* decodeMsg();virtu…

西瓜书《机器学习》符号表KaTex表示

写这篇post的缘故是最近整理机器学习的相关公式&#xff0c;经常要用到KaTex, 但网络上搜索到的西瓜书符号表的表示有些并不准确或不严谨&#xff0c;本着严谨治学的态度&#xff0c;整理了一下符号表的KaTex表示&#xff0c;希望有所帮助,整理过程中参考了《南瓜书》和 KaTex官…

Flutter TextField和Button组件开发登录页面案例

In this section, we’ll go through building a basic login screen using the Button and TextField widgets. We’ll follow a step-bystep approach, allowing you to code along and understand each part of the process. Let’s get started! 在本节中&#xff0c;我们…

软件系统建设方案书(word参考模板)

1 引言 1.1 编写目的 1.2 项目概述 1.3 名词解释 2 项目背景 3 业务分析 3.1 业务需求 3.2 业务需求分析与解决思路 3.3 数据需求分析【可选】 4 项目建设总体规划【可选】 4.1 系统定位【可选】 4.2 系统建设规划 5 建设目标 5.1 总体目标 5.2 分阶段目标【可选】 5.2.1 业务目…

ctfshow(259->261)--反序列化漏洞--原生类与更多魔术方法

Web259 进入界面&#xff0c;回显如下&#xff1a; highlight_file(__FILE__);$vip unserialize($_GET[vip]); //vip can get flag one key $vip->getFlag();题干里还提示了网站有一个flag.php界面&#xff0c;源代码如下&#xff1a; $xff explode(,, $_SERVER[HTTP_X…

Docker容器操作

Docker容器操作 启动容器 docker run -it 镜像名(镜像id) bash当利用docker run来创建容器时&#xff0c;Docker在后台运行的标准操作包括&#xff1a; 检查本地是否存在指定的镜像&#xff0c;不存在就从公有仓库中下载利用镜像创建并启动一个容器分配一个文件系统&#xf…

C语言实现Go的defer功能

之前笔者写了一篇博文C实现Go的defer功能&#xff0c;介绍了如何在C语言中实现Go的defer功能&#xff0c;那在C语言中是否也可以实现这样的功能呢&#xff1f;本文就将介绍一下如何在C语言中实现Go的defer功能。 我们还是使用C实现Go的defer功能中的示例&#xff1a; void te…

医院信息化与智能化系统(9)

医院信息化与智能化系统(9) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应的…