【问题标题】:request.files is empty when uploading a list of files with Flask使用 Flask 上传文件列表时 request.files 为空
【发布时间】:2021-06-02 03:52:56
【问题描述】:

我需要将多个文件上传到列表中的烧瓶端点。但是,当我尝试上传文件列表时,request.files 为空,即使该列表仅包含一个元素。看看这个最小的例子:

from flask import Flask, request
app = Flask(__name__)


@app.route('/', methods=['POST'])
def hello_world():
    assert len(request.files) > 0
    return 'Hello, World'


data_1 = {
    'a': '42',
    'file:': open('blue.jpg', mode='rb'),
    'text': 'this is blue',
}
data_2 = {
    'a': '42',
    'gallery': [{
        'file:': open('blue.jpg', mode='rb'),
        'text': 'this is blue',
    }],
}
client = app.test_client()
res = client.post('/', data=data_1, content_type='multipart/form-data')
assert res.status_code == 200  # all fine here
res = client.post('/', data=data_2, content_type='multipart/form-data')
assert res.status_code == 200  # fails

最后一个断言失败:

[2021-03-03 15:29:46,597] ERROR in app: Exception on / [POST]
Traceback (most recent call last):
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/wsontopski/PycharmProjects/pythonProject1/venv/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/wsontopski/PycharmProjects/pythonProject1/main.py", line 7, in hello_world
    assert len(request.files) > 0
AssertionError
Traceback (most recent call last):
  File "/home/wsontopski/PycharmProjects/pythonProject1/main.py", line 27, in <module>
    assert res.status_code == 200
AssertionError

你知道我该如何解决这个问题吗?

【问题讨论】:

    标签: python python-3.x flask file-upload


    【解决方案1】:

    第二个请求的问题是您试图发送一个文件数组以及一些不可能的数据。如果您看到 request.post() 方法的请求结构,它看起来像这样:

    {
        "args": {},
        "data": "",
        "files": {},
        "form": {
           
        },
        "headers": {
        },
        "json": null,
        "origin": "",
        "url": ""
    }
    

    因此,您必须将所有文件发送到数组之外(在 files 参数中),而您的文本应该以“form”参数形式出现。要发送多个文件,您可以执行以下操作:

    >>> url = 'https://httpbin.org/post'
    >>> multiple_files = [
    ...     ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
    ...     ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
    >>> r = requests.post(url, files=multiple_files)
    

    来源:https://requests.readthedocs.io/en/master/user/advanced/#post-multiple-multipart-encoded-files

    编辑 1: 对于测试客户端,您必须创建如下数据对象:

    data_1 = {
        'a': '42',
        'blue:': open('blue.jpg', mode='rb'),
        'red:': open('red.jpg', mode='rb'),
        'text': 'this is blue',
    }
    

    【讨论】:

    • 感谢您的回答!但是如何使用 Flask 测试客户端来做到这一点? files 不是 client.post() 的有效关键字参数。
    • 我知道多个图像的不同键可以工作。我想知道是否有任何使用图像列表的解决方案。
    • 查看post的请求结构后我不这么认为
    【解决方案2】:

    我解决了问题:使用MultiDict 解决了问题:

    data_1 = {
        'a': '42',
        'file': open('blue.jpg', mode='rb'),
        'file2': open('blue.jpg', mode='rb'),
        'text': 'this is blue',
    }
    data_2 = MultiDict([
        ('a', '42'),
        ('file', open('blue.jpg', mode='rb')),
        ('file', open('blue.jpg', mode='rb')),
        ('text', 'this is blue'),
    ])
    
    client = app.test_client()
    res = client.post('/', data=data_1, content_type='multipart/form-data')
    assert res.status_code == 200
    
    res = client.post('/', data=data_2, content_type='multipart/form-data')
    assert res.status_code == 200
    
    

    输出:

    []
    [<FileStorage: 'blue.jpg' ('image/jpeg')>, <FileStorage: 'blue.jpg' ('image/jpeg')>]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-16
      • 2018-12-30
      • 2018-05-28
      • 2011-11-09
      • 2012-02-13
      • 1970-01-01
      • 2011-01-01
      • 2015-04-12
      相关资源
      最近更新 更多