深入FastAPI:表单和文件上传详解

引言

大家好,我是GISerLiu 😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年11月学习赛的FastAPI学习总结文档;在实际开发中,我们经常需要处理表单数据和文件上传。本文将深入探讨如何在 FastAPI 中处理表单和文件,并通过详细的代码示例和解释,帮助读者由浅入深地理解这些概念。 💕💕😊


一、表单数据的处理

1. 表单数据的基本概念

在 Web 开发中,表单数据通常是通过 HTML 表单提交的。与 JSON 数据不同,表单数据通常使用 application/x-www-form-urlencodedmultipart/form-data 编码格式。FastAPI 提供了 Form 类来处理这些表单数据。

① 安装依赖

要使用 FastAPI 处理表单数据,首先需要安装 python-multipart 库。这个库提供了对表单数据的解析支持。

pip install python-multipart

② 使用 Form 类

Form 类是 FastAPI 中用于声明表单字段的类。与 Body 类似,Form 类允许你定义表单字段的类型和验证规则。

from fastapi import FastAPI, Form
import uvicorn

app = FastAPI()

@app.post("/login/")
async def login(username: str = Form(), password: str = Form()):
    """
    处理用户登录请求,接收表单字段 username 和 password
    """
    return {"username": username}


if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)
  • Form继承自Body类
  • 声明表单体要显式使用 Form ,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。
  • 规范要求字段必须命名为 username 和 password,并通过表单字段发送,不能用 JSON。

在这个例子中,usernamepassword 是通过表单提交的字段。FastAPI 会自动解析这些字段,并将其作为函数参数传递。下面是测试效果:

开发者可在一个路径操作中声明多个 Form 参数,但不能同时声明要接收 JSON 的 Body 字段。因为此时请求体的编码是 application/x-www-form-urlencoded,不是 application/json。这不是 FastAPI 的问题,而是 HTTP 协议的规定。****😊

2. 表单数据的验证

与 JSON 数据类似,表单数据也可以进行验证。FastAPI 提供了丰富的验证功能,可以通过 Form 类来实现。

from fastapi import FastAPI, Form, HTTPException
import uvicorn

app = FastAPI()

@app.post("/login/")
async def login(username: str = Form(min_length=4), password: str = Form(min_length=6)):
    """
    处理用户登录请求,验证 username 和 password 的长度
    """
    return {"username": username}


if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

在这个例子中,我们通过 Form 类的参数 min_length 来验证 usernamepassword 的最小长度。如果验证失败,FastAPI 会自动返回 400 错误。验证失败案例如下:


二、文件上传的处理

1. 文件上传的基本概念

在 Web 开发中,文件上传是一个常见的需求。FastAPI 提供了 UploadFile 类来处理文件上传。UploadFile 类提供了对上传文件的访问和操作方法。

① 安装依赖

与表单数据处理类似,文件上传也需要 python-multipart 库的支持。

pip install python-multipart
② 使用 UploadFile 类

UploadFile 类是 FastAPI 中用于处理文件上传的类。它提供了对上传文件的访问和操作方法。

from fastapi import FastAPI, UploadFile, HTTPException
import uvicorn

app = FastAPI()

@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    """
    处理文件上传请求,返回上传文件的详细信息
    """
    # 读取文件内容
    contents = await file.read()
    
    # 统计文件内容的字节数
    content_bytes = len(contents)
    
    # 尝试解码文件内容为字符串,并统计字符数
    try:
        content_chars = len(contents.decode('utf-8'))
    except UnicodeDecodeError:
        content_chars = None
    
    # 检查文件类型
    if file.content_type.startswith("image/"):
        file_content_info = "Binary image content"
    elif content_chars is not None:
        file_content_info = contents.decode('utf-8')
    else:
        file_content_info = "Binary content"
    
    # 返回文件的详细信息
    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size_in_bytes": content_bytes,
        "size_in_chars": content_chars,
        "file_content_info": file_content_info
    }

if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

这个代码会读取文件,检查文件类型并且输出一些统计信息!

测试结果如下:

如上图所示,测试通过@!👌🎉

2. 文件上传的验证

与表单数据类似,文件上传也可以进行验证。FastAPI 提供了丰富的验证功能,可以通过 UploadFile 类来实现。

from fastapi import FastAPI, UploadFile, HTTPException
import uvicorn

app = FastAPI()

@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    """
    处理文件上传请求,验证文件类型并返回上传文件的详细信息
    """
    # 验证文件类型
    if not file.content_type.startswith("image/"):
        raise HTTPException(status_code=400, detail="File must be an image")
    
    # 读取文件内容
    contents = await file.read()
    
    # 统计文件内容的字节数
    content_bytes = len(contents)
    
    # 尝试解码文件内容为字符串,并统计字符数
    try:
        content_chars = len(contents.decode('utf-8'))
    except UnicodeDecodeError:
        content_chars = None
    
    # 检查文件类型
    if file.content_type.startswith("image/"):
        file_content_info = "Binary image content"
    elif content_chars is not None:
        file_content_info = contents.decode('utf-8')
    else:
        file_content_info = "Binary content"
    
    # 返回文件的详细信息
    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size_in_bytes": content_bytes,
        "size_in_chars": content_chars,
        "file_content_info": file_content_info
    }

if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

在这个例子中,我们通过 UploadFilecontent_type 属性来验证上传文件的类型。如果文件不是图片类型,FastAPI 会自动返回 400 错误。

下面是测试案例:

这里作者尝试上传一个csv文件,结果报错!如此一来,测试通过!👌

3. 多文件上传

FastAPI 支持同时上传多个文件。开发者可以通过声明一个包含 UploadFile 对象的列表来实现多文件上传。这里我们创建一个支持多种格式文件列表上传的Demo!

from fastapi import FastAPI, UploadFile, HTTPException
import uvicorn

app = FastAPI()

@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
    """
    处理多文件上传请求,返回上传文件的详细信息列表
    """
    uploaded_files_info = []
    
    for file in files:
        # 读取文件内容
        contents = await file.read()
        
        # 统计文件内容的字节数
        content_bytes = len(contents)
        
        # 尝试解码文件内容为字符串,并统计字符数
        try:
            content_chars = len(contents.decode('utf-8'))
        except UnicodeDecodeError:
            content_chars = None
        
        # 检查文件类型
        if file.content_type.startswith("image/"):
            file_content_info = "Binary image content"
        elif content_chars is not None:
            file_content_info = contents.decode('utf-8')
        else:
            file_content_info = "Binary content"
        
        # 添加文件的详细信息到列表中
        uploaded_files_info.append({
            "filename": file.filename,
            "content_type": file.content_type,
            "size_in_bytes": content_bytes,
            "size_in_chars": content_chars,
            "file_content_info": file_content_info
        })
    
    # 返回所有上传文件的详细信息
    return {"uploaded_files_info": uploaded_files_info}

if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

在这个例子中,files 是一个包含多个 UploadFile 对象的列表。FastAPI 会自动解析这些文件,并将其作为列表传递给函数。

下面测试案例中,我们选择上传机器学习模型文件(.pt),csv文件和markdown格式的文件;

4. 可选文件上传

在某些情况下,你可能希望文件上传是可选的。FastAPI 允许你通过设置默认值为 None 来实现可选文件上传。

from fastapi import FastAPI, UploadFile, HTTPException, File, Form
import uvicorn

app = FastAPI()

@app.post("/uploadfile/")
async def create_upload_file(
    file: UploadFile | None = File(None),  # 可选文件上传
    description: str = Form(...)  # 必填的表单字段
):
    """
    处理可选文件上传请求,如果未上传文件,返回提示信息;否则返回上传文件的详细信息
    """
    if not file:
        return {"message": "No upload file sent"}
    
    # 读取文件内容
    contents = await file.read()
    
    # 统计文件内容的字节数
    content_bytes = len(contents)
    
    # 尝试解码文件内容为字符串,并统计字符数
    try:
        content_chars = len(contents.decode('utf-8'))
    except UnicodeDecodeError:
        content_chars = None
    
    # 检查文件类型
    if file.content_type.startswith("image/"):
        file_content_info = "Binary image content"
    elif content_chars is not None:
        file_content_info = contents.decode('utf-8')
    else:
        file_content_info = "Binary content"
    
    # 返回文件的详细信息
    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size_in_bytes": content_bytes,
        "size_in_chars": content_chars,
        "file_content_info": file_content_info,
        "description": description  # 返回表单字段
    }

if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

在这个例子中,file 是一个可选的文件上传参数。如果用户没有上传文件,FastAPI 会自动将 file 设置为 None

这里必须得有个能上传的参数,不然会报错;


三、结合表单和文件上传

在大多数应用场景中,我们可能需要同时处理表单字段和文件上传。FastAPI 允许开发者在同一个路径操作中声明多个 FormFile 参数。下面作者将给出一个完整的Demo,各位可以在其上进行修改测试;

from fastapi import FastAPI, File, Form, UploadFile, HTTPException
from fastapi.responses import JSONResponse
import uvicorn
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

@app.post("/upload/")
async def upload_file_and_form(
    file: UploadFile = File(None),  # 可选文件上传
    token: str = Form(...),  # 必填表单字段
    username: str = Form(min_length=4),  # 表单字段,最小长度为4
    password: str = Form(min_length=6)  # 表单字段,最小长度为6
):
    """
    处理文件和表单字段上传请求,返回文件名和表单字段值
    """
    # 检查文件是否为空
    if file is None or file.filename == "":
        return JSONResponse(content={"message": "No upload file sent"}, status_code=200)
    
    try:
        # 读取文件内容
        contents = await file.read()
        
        # 统计文件内容的字节数
        content_bytes = len(contents)
        
        # 尝试解码文件内容为字符串,并统计字符数
        try:
            content_chars = len(contents.decode('utf-8'))
        except UnicodeDecodeError:
            content_chars = None
        
        # 检查文件类型
        if file.content_type.startswith("image/"):
            file_content_info = "Binary image content"
        elif content_chars is not None:
            file_content_info = contents.decode('utf-8')
        else:
            file_content_info = "Binary content"
        
        # 返回文件和表单字段的详细信息
        return {
            "token": token,
            "username": username,
            "password": password,
            "filename": file.filename,
            "content_type": file.content_type,
            "size_in_bytes": content_bytes,
            "size_in_chars": content_chars,
            "file_content_info": file_content_info
        }
    except Exception as e:
        logger.error(f"Error processing file: {e}")
        raise HTTPException(status_code=500, detail="Error processing file")

if __name__ == '__main__':
    # 使用 uvicorn 运行 FastAPI 应用
    uvicorn.run(app, host='127.0.0.1', port=8009)

代码逻辑很简单,作者就不解释了,有问题可自行GPT;

在这个例子中,我们同时处理了文件上传和表单字段 token。FastAPI 会自动解析这些数据,并将其作为函数参数传递。

测试通过,没什么问题!😊

在全栈开发中,这些基础API很容易掌握,我们需要重点记忆的是业务流程,熟悉了业务流程,经过两个项目的实践,便很容易开发后端接口!😎

OK,今天就学习到这!👌


相关链接

  • 项目地址:FastAPI-CookBook
  • 相关文档:专栏地址
  • 作者主页:GISer Liu-CSDN博客

thank_watch

如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习HTML第三十三天

学习文章目录 一.fieldset 与 legend 的使用(了解)二.表单总结三.框架标签 一.fieldset 与 legend 的使用(了解) fieldset 可以为表单控件分组、 legend 标签是分组的标题 二.表单总结 form表单: action 属性&#…

使用NAS开启无纸化办公,Docker部署开源文档管理系统『Paperless-ngx』

使用NAS开启无纸化办公,Docker部署开源文档管理系统『Paperless-ngx』 哈喽小伙伴们好,我是Stark-C~ 对于文案类的办公场景来说,手头堆放最多的可能就是各种文档文件,以及各种用过的打印废纸。 这么多年来,不管是领…

SQL基础入门——SQL基础语法

1. 数据库、表、列的创建与管理 在SQL中,数据库是一个数据的集合,包含了多个表、视图、索引、存储过程等对象。每个表由若干列(字段)组成,表中的数据行代表记录。管理数据库和表的结构是SQL的基础操作。 1.1 创建数据…

YOLOv11融合PIDNet中的PagFM模块及相关改进思路

YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》 一、 模块介绍 论文链接:https://arxiv.org/pdf/2…

什么是代理,nodenginx前端代理详解

一. 什么是代理? 代理就是通过一个特殊的网络服务去访问另一网络服务的一种间接访问方式。像我们不能直接访问国外的网站,只能使用VPN,就是使用了代理 二. 前端为什么要用代理? 首先明确以下两个概念 (1&#xff09…

BERT解析

BERT项目 我在BERT添加注释和部分推理代码 main.py vocab WordVocab.load_vocab(args.vocab_path)#加载vocab那么这个加载的二进制是什么呢? 1. 加载数据集 继承关系:TorchVocab --> Vocab --> WordVocab TorchVocab 该类主要是定义了一个词…

《独立开发:Spring 框架的综合应用》

一、Spring 框架概述 Spring 是一个分层的 Java SE/EE full-stack 轻量级开源框架,以 IoC 和 AOP 为内核,具有方便解耦、方便集成优秀框架、降低 Java EE API 使用难度等优点。 Spring 框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。它是…

JMeter如何配置分布式?

一、复制两个代理机 二、代理机一 在第一个D:\install\apache-jmeter1\bin目录下,修改"jmeter.properties"文件 搜索"server_port"改成"server_port1999", "#server.rmi.ssl.disablefalse"改成"server.r…

多目标优化算法——多目标粒子群优化算法(MOPSO)

Handling Multiple Objectives With Particle Swarm Optimization(多目标粒子群优化算法) 一、摘要: 本文提出了一种将帕累托优势引入粒子群优化算法的方法,使该算法能够处理具有多个目标函数的问题。与目前其他将粒子群算法扩展…

物联网实验室建设方案

一、物联网实验室建设 (1) 基础理论教学云平台 唯众基础理论教学云平台是一个专为物联网相关专业教学打造的综合性在线教学平台。该平台凭借先进的技术架构和丰富的教学资源,为师生提供了一个高效、便捷、互动的学习环境。以下是该平台的主要特点和功能描述&#…

【汇编语言】call 和 ret 指令(一) —— 探讨汇编中的ret和retf指令以及call指令及其多种转移方式

文章目录 前言1. ret 和 retf1.1 ret 指令1.1.1 功能与理解1.1.2 程序演示 1.2 retf 指令1.2.1 功能与理解1.2.2 程序演示 2. call 指令3. 依据位移进行转移的call指令3.1 格式与功能3.1.1 格式3.1.2 功能 3.2 理解指令 4. 转移的目的地址在指令中的call指令4.1 格式与功能4.1.…

(免费送源码)计算机毕业设计原创定制:Java+B/S+SSM+Web前端开发技术+IDEA+MySQL+Navicat 有风小院

摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对有风小院等问题,对有风小院信息…

# DBeaver 连接hive数仓

前提 前提是基于hadoop的hive服务已经启动,其中hive的服务包括metastore元数据服务和hiveserver2服务已经启动。hiveserver2服务在默认端口10000启动,且通过telnet xx.xx.xx.xx 10000 能通。 满足以上要求后,再可以看以下连接文档&#xff…

数据结构:链表进阶

链表进阶 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现 3.链表面试题4.LinkedList的使用5.1 什么是LinkedList4.2 LinkedList的使用 5. ArrayList和LinkedList的区别 1. ArrayList的缺陷 通过源码知道,ArrayList底层使用数组来存储元素&#xff1…

DVWA 在 Windows 环境下的部署指南

目录预览 一、靶场介绍二、前置准备1. 环境准备2.靶场下载 三、安装步骤1.配置Phpstudy2.配置数据库3.配置DVWA4.登入DVWA靶场 四、参考链接 一、靶场介绍 DVWA 一共包含了十个攻击模块,分别是: Brute Force(暴力(破解&#xff…

关于如何在k8s中搭建一个nsfw黄图鉴定模型

随着现在应用内图片越来越多,安全审查也是必不可少的一个操作了 下面手把手教你如何将huggingface中的黄图检测模型部署到自己的服务器上去 1.找到对应的模型 nsfw_image_detection 2.在本地先验证如何使用 首先安装transformers python库 pip install transform…

【linux】tar命令讲解笔记

Linux tar 命令 Linux tar(英文全拼:tape archive )命令用于备份文件。 tar 是 Linux 和 Unix 系统中用于归档文件和目录的强大命令行工具。 tar 名字来自 "tape archive"(磁带归档),最初用于将…

JVM_垃圾收集器详解

1、 前言 JVM就是Java虚拟机,说白了就是为了屏蔽底层操作系统的不一致而设计出来的一个虚拟机,让用户更加专注上层,而不用在乎下层的一个产品。这就是JVM的跨平台,一次编译,到处运行。 而JVM中的核心功能其实就是自动…

Android音频框架总结

1、AudioFlinger:接收多个APP的数据,合并下发;是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完 成。 AudioFlinger主要包含3个主…

深度学习:自然语言处理

一、引言 自然语言处理作为人工智能领域的关键分支,致力于使计算机能够理解、分析和生成人类语言。近年来,随着深度学习技术的迅猛发展,自然语言处理取得了前所未有的突破,一系列创新技术和应用不断涌现,极大地推动了…