上传多个文件 UploadFiles FastAPI

Posted

技术标签:

【中文标题】上传多个文件 UploadFiles FastAPI【英文标题】:uploading multiple files UploadFiles FastAPI 【发布时间】:2020-07-28 16:16:04 【问题描述】:

示例

这是我的代码:

from typing import  List
from fastapi import FastAPI, File, UploadFile
import asyncio
import concurrent.futures

app = FastAPI()
@app.post("/send_images")
async def update_item(
    files: List[UploadFile] = File(...),
):
    return "res": len(files)

我向这个服务器发送请求(这些特定的 url 只是这里的例子):

import requests
import os 
import json
import numpy as np
import time
import io
import httpx
import asyncio
from datetime import datetime
import pandas as pd

from random import shuffle
import pandas as pd
import urllib
import io
from PIL import Image
from matplotlib import pyplot as plt
import concurrent.futures

urls = ['https://sun9-63.userapi.com/c638920/v638920705/1a54d/xSREwpakJD4.jpg',
 'https://sun9-28.userapi.com/c854024/v854024084/1160d8/LDMVHYgguAw.jpg',
 'https://sun9-54.userapi.com/c854220/v854220084/111f66/LdcbEpPR6tg.jpg',
 'https://sun9-40.userapi.com/c841420/v841420283/4c8bb/Mii6GSCrmpo.jpg',
 'https://sun6-16.userapi.com/CPQpllJ0KtaArvQKkPsHTZDCupqjRJ_8l07ejA/iyg2hRR_kM4.jpg',
 'https://sun9-1.userapi.com/c638920/v638920705/1a53b/SMta6Bv-k7s.jpg',
 'https://sun9-36.userapi.com/c857332/v857332580/56ad/rJCGKFw03FQ.jpg',
 'https://sun6-14.userapi.com/iPsfmW0ibE8RsMh0k2lUFdRxHZ4Q41yctB7L3A/ajJHY3WN6Xg.jpg',
 'https://sun9-28.userapi.com/c854324/v854324383/1c1dc3/UuFigBF7WDI.jpg',
 'https://sun6-16.userapi.com/UVXVAT-tYudG5_24FMaBWTB9vyW8daSrO2WPFQ/RMjv7JZvowA.jpg']

os.environ['NO_PROXY'] = '127.0.0.1'

async def request_get_4(list_urls):
    async with httpx.AsyncClient() as client:
        r = httpx.post("http://127.0.0.1:8001/send_images", files=f'num_ind': el for ind, el in enumerate(list_urls))
        print(r.text)
        return r

async def request_get_3(url):
    async with httpx.AsyncClient() as client:
        return await client.get(url)
    
from collections import defaultdict

async def main():
    start = datetime.now()
    tasks = [asyncio.create_task(request_get_3(url)) for url in urls[0:10]]
    result = await asyncio.gather(*tasks)
    
    data_to_send = []
    for ind, resp in enumerate(result):
        if resp.status_code == 200:
            image_bytes = io.BytesIO(resp.content)
            image_bytes.seek(0)
            data_to_send.append(image_bytes)
        
    end = datetime.now()
    print(result)
    print(len(data_to_send))

    batch_size = 2
    batch_num = len(data_to_send) // batch_size
    tasks = [asyncio.create_task(request_get_4(data_to_send[i * batch_size: (i+1) * batch_size])) for i in range(batch_num)]
    result = await asyncio.gather(*tasks)
    
    left_data = data_to_send[batch_size*(batch_num):]
    print(len(left_data))
    print(result)

asyncio.run(main())

我正在尝试加载包含在 url 中的图像,然后形成它们的批次并将它们发送到 FastAPI 服务器。但它不起作用。 我收到以下错误:

"detail":["loc":["body","files"],"msg":"field required","type":"value_error.missing"]

如何解决我的问题并能够通过 httpx 将多个文件发送到 FastAPI?

【问题讨论】:

我的猜测是您的端点需要 list 的文件,而您通过 httpx.post 请求传递字典。试试files=[f for f in downloaded_files] 之类的东西,顺便说一句,您在发送它们之前似乎没有下载它们 在 https.post 文件中的参数需要字典。 为什么你认为我不下载网址?我使用 httpx.get。 所以,是的,这是 httpx 模块的限制!现在它不能在 post 请求中发送多个文件! 对不起,我看错了,虽然 list_urls 仍然是上面的列表。另外,我不认为这是 httpx 的限制。 python-httpx.org/advanced/#multipart-file-encoding 表示它接受带有元组的字典。这行得通吗? 【参考方案1】:

问题在于 HTTPX 0.13.3 不支持多个文件上传,因为此参数希望字典和字典不能具有相同的键值。

我们可以使用这个 pull request https://github.com/encode/httpx/pull/1032/files 来解决这个问题(现在它也可以接受 List[Tuple[str, FileTypes]]])!

更新: 这个问题现在解决了!

更新2: 这里我展示了我如何使用 httpx 处理不同的请求:

async def request_post_batch(fastapi_url: str, url_content_batch: List[BinaryIO]) -> httpx.Response:
    """
    Send batch to FastAPI server.
    """
    async with httpx.AsyncClient(timeout=httpx.Timeout(100.0)) as client:
        r = await client.post(
            fastapi_url,
            files=[('bytes_image', url_content) for url_content in url_content_batch]
        )
        return r


async def request_post_logs(logstash_url: str, logs: List[Dict]) -> httpx.Response:
    """
    Send logs to logstash
    """
    async with httpx.AsyncClient(timeout=httpx.Timeout(100.0)) as client:
        r = await client.post(
            logstash_url,
            json=logs
        )
        return r

【讨论】:

示例,示例,示例 :-) 请 :-) 你想要什么例子?

以上是关于上传多个文件 UploadFiles FastAPI的主要内容,如果未能解决你的问题,请参考以下文章

axios 带验证参数上传

如何使用快速上传文件?

Gin框架之文件上传

Unity--上传下载文件并保存到本地

Unity--上传下载文件并保存到本地

【layui】上传文件时进行校验是不是选择文件