我正在制作一个需要上传文件的 REST API。出于测试目的,我通过邮递员上传文件,但我不知道如何访问服务器端的文件。我能够检索
_dict
进行身份验证,但对于 file
,它返回 None
。
#arguments - create, delete, view, list, search, upload, download
@app.post("/incident-resource/{service}")
async def incident_resource_service_handler(service, request: Request):
try:
session = Session()
reqDataForm: FormData = await request.form()
reqData = reqDataForm._dict
file = reqDataForm.get('resource') # in form(key='resource', value=abc.jpeg)
print(type(file)) #< class 'NoneType' >
user = usr_getAuthenticatedUser(session, reqData)
userRole = getRole(session, user.role_id)
except Exception as e:
session.rollback()
return handleException(e)
根据文档,“文件将作为
form
数据上传”,您应该通过在端点中声明类型为bytes
或UploadFile
来接收它们(请参阅这个答案和这个回答)。如果您需要随文件一起发送其他数据(例如 form
或 JSON 数据),您也可以查看 此答案。
但是,如果您需要按照解决问题中的问题的方式来执行此操作,即使用
request.form()
解析原始请求正文,请查看 这个答案 的选项 1 和下面的示例。根据Starlette 的文档,您可以获得文件名和内容,如下所示。无论在客户端使用什么键名来声明数据,您也必须在服务器端使用相同的键名,以便从form
检索数据。下面的file
用作文件数据的键。
@app.post('/upload')
async def create_file(request: Request):
form = await request.form()
filename = form['file'].filename
contents = await form['file'].read()
但是,最好在端点中声明预期的参数(例如文件和表单数据),而不是使用
request.form()
,因为它允许您定义是否需要参数(因此,例外如果客户端在其请求中未包含此类参数,则会引发此错误)及其类型(即 str
、int
、等),如果客户端请求不包含正确类型的数据,这将再次引发异常。如果您使用 async def
定义端点,则可以使用 aiofiles
(如此处所示)将文件保存到磁盘;否则,请参阅此答案。
from fastapi import FastAPI, Request, UploadFile, HTTPException, status
from fastapi.responses import HTMLResponse
import aiofiles
app = FastAPI()
@app.post('/upload')
async def upload(file: UploadFile):
try:
contents = await file.read()
async with aiofiles.open(file.filename, 'wb') as f:
await f.write(contents)
except Exception:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail='There was an error uploading the file',
)
finally:
await file.close()
return {'message': f'Successfuly uploaded {file.filename}'}
# Access the form at 'http://127.0.0.1:8000/' from your browser
@app.get('/')
async def main():
content = '''
<body>
<form action='/upload' enctype='multipart/form-data' method='post'>
<input name='file' type='file'>
<input type='submit'>
</form>
</body>
'''
return HTMLResponse(content=content)
from fastapi import FastAPI, Request, UploadFile, HTTPException, status
from fastapi.responses import HTMLResponse
from typing import List
import aiofiles
app = FastAPI()
@app.post('/upload')
async def upload(files: List[UploadFile]):
for file in files:
try:
contents = await file.read()
async with aiofiles.open(file.filename, 'wb') as f:
await f.write(contents)
except Exception:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail='There was an error uploading the file(s)',
)
finally:
await file.close()
return {'message': f'Successfuly uploaded {[file.filename for file in files]}'}
# Access the form at 'http://127.0.0.1:8000/' from your browser
@app.get('/')
async def main():
content = '''
<body>
<form action='/upload' enctype='multipart/form-data' method='post'>
<input name='files' type='file' multiple>
<input type='submit'>
</form>
</body>
'''
return HTMLResponse(content=content)
就我而言,不需要复杂性,甚至不需要 JavaScript。 我要做的就是将 enctype 添加到 html 表单中,如下所示:
<form method="POST" enctype="multipart/form-data">
<div class="mb-3">
<h5>Medical Data:</h5>
<input type="file" multiple id="fileid1" placeholder="Job location" name="file" value="{{file}}" class="form-control">
</div>
@router.post("/add-medical-record/")
async def create_job(request: Request, file: UploadFile = None, db: Session = Depends(get_db)):