前面几篇主要讲解的是fastapi在接收JSON数据时,该如何进行处理。但是在Web中存在表单和文件两种类型的数据传输情况。本篇中主要针对这两种数据类型进行讲解。

表单数据

要使用表单,需预先安装python-multipart包。

# 激活虚拟环境
cd env/Scripts
activate
# 安装python-multipart包
pip install python-multipart

使用方法

要获取表单数据,就是要在路径操作函数中定义响应的变量,且该变量的默认值为Form函数的返回值。
下面是后端代码:

from random import paretovariate
from fastapi import FastAPI
# 演示获取表单数据的步骤
# 第一步:导入Form函数
from fastapi import Form
# 第二步:创建一个FastAPI类的实例对象
app = FastAPI()
# 第三步:创建一个路径装饰器
@app.post("/register")
# 第四步:创建一个路径操作函数,声明Form表单变量
async def create_user(username: str = Form(), password: str = Form()):
    return {
        "result": "register successfully",
        "username": username,
        "password": password
    }
# 第五步:运行服务器
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app="main:app", host="127.0.0.1", port=8080, reload=True)

下面是前端测试页面代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>register</title>
</head>

<body>
    <h2>这是一个测试fastapi获取表单数据的页面</h2>
    <!--action路径需要和后端定义的路径匹配!!!-->
    <form action="http://127.0.0.1:8080/register" method="post">
        <label for="name">用户名:</label><input type="text" name="username" id="name"><br>
        <label for="pwd">密码:</label><input type="password" name="password" id="pwd"><br>
        <button type="submit">注册</button>
    </form>
</body>

</html>

下面是测试结果:

python 接收html form表单 python获取form表单数据_html


python 接收html form表单 python获取form表单数据_fastapi_02

表单字段注意事项

根据HTTP协议规定一次请求体中不能具有两种编码格式。
所以在一个路径操作函数中可以声明多个Form参数,但不能同时声明要接收JSON的Body字段。这是因为Form字段的编码是application/x-www-form-urlencoded,而Body字段的编码是application/json。

文件数据

File函数方式

使用File函数方式和使用Form函数方式相同,在路径操作函数中将文件参数的默认值设定为File函数的返回值。
下面是后端的代码示例:

# 演示接收文件数据
# File方式,利用File来声明这个变量接收的是一个文件数据
from fastapi import File
@app.post("/file/file")
# 此处的...表示None,...表示省略第一个形参
# filename需要和前端的变量名一致
async def get_file(filename:bytes = File(...)):
    return {"file_size":len(filename)}

下面是前端的代码示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>这是用来演示fastapi接收文件数据的前端演示</h2>
    <form action="http://127.0.0.1:8080/file/file" method="post" enctype="multipart/form-data">
    <!--注意此处filename必须和后端文件参数变量名一致-->
        <label for="file1"></label><input type="file" name="filename" id="file1">
        <button type="submit">上传</button>
    </form>

</body>

</html>

下面是演示结果:

python 接收html form表单 python获取form表单数据_python_03


python 接收html form表单 python获取form表单数据_python_04

UploadFile类方式

利用fastapi包中的UploadFile类,来声明变量的数据类型,以引入文件参数。
后端代码演示如下:

# 演示UploadFile类接收文件数据
# UploadFile方式,利用UploadFile来声明变量的类型
from fastapi import UploadFile
@app.post("/file/uploadfile")
async def get_uploadfile(file:UploadFile):
    # filename:上传文件名字符串(str),例如, myimage.jpg;
    # content_type:内容类型(MIME 类型 / 媒体类型)字符串(str),例如,image/jpeg;
    return{
        "filename":file.filename,
        "content_type":file.content_type
    }

前端代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>这是用来演示fastapi接收文件数据的前端演示</h2>
    <!--form 中包含文件时编码格式应该是multipart/form-data-->
    <form action="http://127.0.0.1:8080/file/uploadfile" method="post" enctype="multipart/form-data">
        <label for="file">文件</label><input type="file" name="file" id="file">
        <button type="submit">上传文件</button>
    </form>
</body>

</html>

演示结果:

python 接收html form表单 python获取form表单数据_html_05


python 接收html form表单 python获取form表单数据_fastapi_06

多文件数据获取

想获取多个文件数据,只需要将接收文件数据的变量类型声明为列表即可。
后端代码如下:

# 演示File和UploadFile接收多文件数据
# 接收多文件时需要将接收文件类型的参数,声明为包含文件的列表形式
from typing import List
@app.post("/files/file")
async def get_files(files:List[bytes]=File(...)):
    return {
        "file_number":len(files)
    }
    
@app.post("/files/uploadfile")
async def get_files(files:List[UploadFile]):
    filesname = [file.filename for file in files]
    return { "filesname":filesname}

前端代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Files</title>
</head>

<body>
    <h2>演示File的多文件数据引用</h2>
    <form action="http://127.0.0.1:8080/files/file" method="post" enctype="multipart/form-data">
        <label for="files">
            文件名:
        </label>
        <input type="file" name="files" id="files" multiple>
        <button type="submit">上传文件</button>
    </form>

    <h2>演示UploadFile的多文件数据引用</h2>
    <form action="http://127.0.0.1:8080/files/uploadfile" method="post" enctype="multipart/form-data">
        <label for="files">
            文件名:
        </label>
        <input type="file" name="files" id="files" multiple>
        <button type="submit">上传文件</button>
    </form>

</body>

</html>

演示结果:

python 接收html form表单 python获取form表单数据_数据_07


python 接收html form表单 python获取form表单数据_fastapi_08


python 接收html form表单 python获取form表单数据_python_09


python 接收html form表单 python获取form表单数据_fastapi_10

File和UploadFile方式的优缺点

方式

优点

缺点

File()

将文件的所有内容都存储在内存里,适用于小型文件

不适合存储大文件

UploadFile

使用spooled文件:存储在内存的文件超出最大上限时,fastapi会把文件存入磁盘。适合处理图像,视频,二进制等大型文件,不会占用所有内存。自带file-like async接口,可以像操作文件一样操作文件数据


表单和文件混合

有时候在一个表单中可能既包含表单数据又包含文件数据,这种情况fastapi也是支持的。只需声明各个数据所对应的数据类型即可。
需要注意的是在前端中对form的编码需设定为multipart/form-data。
后端示例代码

# 演示既接收Form数据又接收文件数据
@app.post("/mixdata")
async def get_mixdata(username=Form(),file:UploadFile=File()):
    return {
        "username":username,
        "filename":file.filename
    }

前端示例代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>这是用来演示fastapi接收混合表单数据的前端演示</h2>
    <!--form 中包含文件时编码格式应该是multipart/form-data-->
    <form action="http://127.0.0.1:8080/mixdata" method="post" enctype="multipart/form-data">
        <label for="username">用户名:</label><input type="text" name="username" id="username"><br>
        <label for="file">文件:</label><input type="file" name="file" id="file"><br>
        <button type="submit">提交</button>
    </form>
</body>

</html>

演示结果:

python 接收html form表单 python获取form表单数据_python_11


python 接收html form表单 python获取form表单数据_后端_12