FastAPI 上传文件需要用到File对象,在定义路径操作时声明File类型的参数,可以声明成bytes 或 UploadFile,下面的示例演示声明成bytes类型
from fastapi import FastAPI, File
from starlette.templating import Jinja2Templates
from starlette.requests import Request
app = FastAPI()
template = Jinja2Templates(directory='templates') # 创建模板对象
@app.get('/upload')
def upload_html(request: Request):
return template.TemplateResponse('upload.html', {'request': request})
@app.post('/uploadfile')
def upload_file(file: bytes = File(...)):
with open('./data/up.pdf', 'wb')as f:
f.write(file)
return 'ok'
upload.html文件的内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="uploadfile" method=post enctype=multipart/form-data>
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
</body>
</html>
上传一个pdf文件,文件被保存到data目录下,由于file的类型标注是bytes类型,因此,服务端拿不到上传文件的名称,只能得到文件的二进制内容,因此可以说这种上传文件的方式不大可能有太多的应用场景,我们了解一下就好。
将文件对象的类型标注设置为UploadFile
import os
from fastapi import FastAPI, File, UploadFile
@app.post('/uploadfile')
async def upload_file(file: UploadFile = File(...)):
with open(os.path.join('./data', file.filename), 'wb')as f:
data = await file.read()
f.write(data)
return 'ok'
UploadFile 支持的下面几个方法都是异步的
相比于将file对象声明成bytes类型,声明成UploadFile有以下几个好处:
前面演示的只是上传文件,还存在一种情况,在提交表单的同时,也要上传文件,修改upload.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="uploadfile" method=post enctype=multipart/form-data>
<input type="text" name="name">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
</body>
</html>
增加一个input控件,修改app.py文件
import os
from fastapi import FastAPI, File, UploadFile, Form
from starlette.templating import Jinja2Templates
from starlette.requests import Request
app = FastAPI()
template = Jinja2Templates(directory='templates') # 创建模板对象
@app.get('/upload')
def upload_html(request: Request):
return template.TemplateResponse('upload.html', {'request': request})
@app.post('/uploadfile')
async def upload_file(file: UploadFile = File(...), name: str = Form(...)):
print(name)
with open(os.path.join('./data', file.filename), 'wb')as f:
data = await file.read()
f.write(data)
return 'ok'
在upload_file 函数里增加name参数,接收form表单里的数据,通过print语句的输出可以看到form表单里的input标签传上来的数据被正确读取了,文件也得到保存。
有两种方式上传多个文件,一种是以列表的方法,另一种是精确匹配的方式,先来看列表的方式,修改uplaod.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="uploadfile" method=post enctype=multipart/form-data>
<input type="file" name="files" multiple>
<input type="file" name="files" multiple>
<input type="submit" value="Upload">
</form>
</body>
</html>
两个file控件的name是相同的,这样在服务端就要使用列表的形式来接收上传的文件
from typing import List
@app.post('/uploadfile')
async def upload_file(files: List[UploadFile] = File(...)):
for file in files:
with open(os.path.join('./data', file.filename), 'wb')as f:
data = await file.read()
f.write(data)
return 'ok'
前端name是files的标签有多个,服务端在定义操作路径时,也要对应的定义一个files的变量,同时类型标注为List,如果所上传的多个文件各有自己的用途,不适合统一处理,那么就可以分开来处理,修改upload.html文件
@app.post('/uploadfile')
async def upload_file(pdf_file: UploadFile = File(...), word_file: UploadFile = File(...)):
print(pdf_file.filename)
print(word_file.filename)
return 'ok'
这样也实现了多个文件同时上传,可以通过前后端的变量来唯一的确认文件进行处理。
QQ交流群: 211426309