简体   繁体   中英

How to Upload File using FastAPI?

I am using FastAPI to upload a file according to the official documentation, as shown below:

@app.post("/create_file/")
async def create_file(file: UploadFile = File(...)):
      file2store = await file.read()
      # some code to store the BytesIO(file2store) to the other database

When I send a request using Python requests library, as shown below:

f = open(".../file.txt", 'rb')
files = {"file": (f.name, f, "multipart/form-data")}
requests.post(url="SERVER_URL/create_file", files=files)

the file2store variable is always empty. Sometimes (rarely seen), it can get the file bytes, but almost all the time it is empty, so I can't restore the file on the other database.

I also tried the bytes rather than UploadFile , but I get the same results. Is there something wrong in my code, or is the way I use FastAPI to upload a file wrong?

Note that the answer below uses synchronous writing for writing the files to disk. If you need async writing, please have a look at this answer . Moreover, if you need to send additional data (such as JSON data) together with uploading the file(s), please have a look at this answer . I would suggest you have a look at this answer as well, which explains the difference between defining an endpoint with def and async def , and demonstrates how to read the contents of an uploaded file when using def (if that's a requirement for your app).

Upload Single File

app.py

import uvicorn
from fastapi import File, UploadFile, FastAPI

app = FastAPI()

@app.post("/upload")
async def upload(file: UploadFile = File(...)):
    try:
        contents = await file.read()
        with open(file.filename, 'wb') as f:
            f.write(contents)
    except Exception:
        return {"message": "There was an error uploading the file"}
    finally:
        await file.close()
        
    return {"message": f"Successfuly uploaded {file.filename}"}
    

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

test.py

import requests

url = 'http://127.0.0.1:8000/upload'
file = {'file': open('images/1.png', 'rb')}
resp = requests.post(url=url, files=file) 
print(resp.json())

Upload Multiple (List of) Files

app.py

import uvicorn
from fastapi import File, UploadFile, FastAPI
from typing import List

app = FastAPI()

@app.post("/upload")
async def upload(files: List[UploadFile] = File(...)):
    for file in files:
        try:
            contents = await file.read()
            with open(file.filename, 'wb') as f:
                f.write(contents)
        except Exception:
            return {"message": "There was an error uploading the file(s)"}
        finally:
            await file.close()

    return {"message": f"Successfuly uploaded {[file.filename for file in files]}"}    

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

test.py

import requests

url = 'http://127.0.0.1:8000/upload'
files = [('files', open('images/1.png', 'rb')), ('files', open('images/2.png', 'rb'))]
resp = requests.post(url=url, files=files) 
print(resp.json())
@app.post("/create_file/")
async def image(image: UploadFile = File(...)):
    print(image.file)
    # print('../'+os.path.isdir(os.getcwd()+"images"),"*************")
    try:
        os.mkdir("images")
        print(os.getcwd())
    except Exception as e:
        print(e) 
    file_name = os.getcwd()+"/images/"+image.filename.replace(" ", "-")
    with open(file_name,'wb+') as f:
        f.write(image.file.read())
        f.close()
   file = jsonable_encoder({"imagePath":file_name})
   new_image = await add_image(file)
   return {"filename": new_image}

Just copy and paste the code it will work perfect.

from fastapi import (
    FastAPI
    UploadFile,
    File,
    status
)
from fastapi.responses import JSONResponse

import aiofiles
app = FastAPI( debug = True ) 

@app.post("/upload_file/", response_description="", response_model = "")
async def result(file:UploadFile = File(...)):
     try:
        async with aiofiles.open(file.filename, 'wb') as out_file:
            content = await file.read()  # async read
            await out_file.write(content)  # async write

    except Exception as e:
        return JSONResponse(
            status_code = status.HTTP_400_BAD_REQUEST,
            content = { 'message' : str(e) }
            )
    else:
        return JSONResponse(
            status_code = status.HTTP_200_OK,
            content = {"result":'result'}
            )

I had worked on it nearly 7-8 months ago, I didn't encounter the problem which you are saying. I had found out that that UploadFile is of type SpooledTemproaryFile and I didn't try reading file asynchronously. Here is the snippet which is being used. I have uploaded all types of files up to 100mb, it is working. I had to save file on server on a specific path

with open(path, 'wb') as f:
    [f.write(chunk) for chunk in iter(lambda: file.file.read(10000), b'')]

In your case I'd suggest reading file and making the post request directly using aiohttp sessions or AsyncClient from httpx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM