FastAPI - 如何通过 HTML 表单上传文件?

问题描述 投票:0回答:2

我正在制作一个需要上传文件的 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)
python forms file-upload fastapi multipartform-data
2个回答
3
投票

根据文档,“文件将作为

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
(如此处所示)将文件保存到磁盘;否则,请参阅此答案

通过 HTML 表单上传单个文件

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)

通过 HTML 表单上传多个文件

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)

0
投票

就我而言,不需要复杂性,甚至不需要 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>

快速 API Python 文件

@router.post("/add-medical-record/")
async def create_job(request: Request, file: UploadFile = None, db: Session = Depends(get_db)):
© www.soinside.com 2019 - 2024. All rights reserved.