为了测试Flask应用程序,我得到了一个烧瓶测试客户端POST请求,文件作为附件
def make_tst_client_service_call1(service_path, method, **kwargs):
_content_type = kwargs.get('content-type','multipart/form-data')
with app.test_client() as client:
return client.open(service_path, method=method,
content_type=_content_type, buffered=True,
follow_redirects=True,**kwargs)
def _publish_a_model(model_name, pom_env):
service_url = u'/publish/'
scc.data['modelname'] = model_name
scc.data['username'] = "BDD Script"
scc.data['instance'] = "BDD Stub Simulation"
scc.data['timestamp'] = datetime.now().strftime('%d-%m-%YT%H:%M')
scc.data['file'] = (open(file_path, 'rb'),file_name)
scc.response = make_tst_client_service_call1(service_url, method, data=scc.data)
处理上述POST请求的Flask Server端点代码就是这样的
@app.route("/publish/", methods=['GET', 'POST'])
def publish():
if request.method == 'POST':
LOG.debug("Publish POST Service is called...")
upload_files = request.files.getlist("file[]")
print "Files :\n",request.files
print "Upload Files:\n",upload_files
return render_response_template()
我得到了这个输出
Files:
ImmutableMultiDict([('file', <FileStorage: u'Single_XML.xml' ('application/xml')>)])
Upload Files:
[]
如果我改变
scc.data['file'] = (open(file_path, 'rb'),file_name)
进入(认为它会处理多个文件)
scc.data['file'] = [(open(file_path, 'rb'),file_name),(open(file_path, 'rb'),file_name1)]
我仍然得到类似的输出:
Files:
ImmutableMultiDict([('file', <FileStorage: u'Single_XML.xml' ('application/xml')>), ('file', <FileStorage: u'Second_XML.xml' ('application/xml')>)])
Upload Files:
[]
问题: 为什么request.files.getlist(“file []”)返回一个空列表? 如何使用flask测试客户端发布多个文件,以便可以使用烧瓶服务器端的 request.files.getlist(“file []”)来检索它?
注意:
由于
已经提到这些链接:
Flask and Werkzeug: Testing a post request with custom headers
Python - What type is flask.request.files.stream supposed to be?
答案 0 :(得分:6)
您将文件作为名为file
的参数发送,因此您无法使用名称file[]
查找它们。如果要将名为file
的所有文件作为列表,则应使用此:
upload_files = request.files.getlist("file")
另一方面,如果你真的想从file[]
读取它们,那么你需要像这样发送它们:
scc.data['file[]'] = # ...
(file[]
语法来自PHP,它仅在客户端使用。当您将名称相同的参数发送到服务器时,您仍然可以使用$_FILES['file']
访问它们。)
答案 1 :(得分:2)
Lukas已经解决了这个问题,只是提供这些信息,因为它可能有助于某人
Werkzeug客户端通过在MultiDict中存储请求数据来做一些聪明的事情
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
class MultiDict(TypeConversionDict):
"""A :class:`MultiDict` is a dictionary subclass customized to deal with
multiple values for the same key which is for example used by the parsing
functions in the wrappers. This is necessary because some HTML form
elements pass multiple values for the same key.
:class:`MultiDict` implements all standard dictionary methods.
Internally, it saves all values for a key as a list, but the standard dict
access methods will only return the first value for a key. If you want to
gain access to the other values, too, you have to use the `list` methods as
explained below.
getList调用在“requests”字典中查找给定键。如果密钥不存在,则返回空列表。
def getlist(self, key, type=None):
"""Return the list of items for a given key. If that key is not in the
`MultiDict`, the return value will be an empty list. Just as `get`
`getlist` accepts a `type` parameter. All items will be converted
with the callable defined there.
:param key: The key to be looked up.
:param type: A callable that is used to cast the value in the
:class:`MultiDict`. If a :exc:`ValueError` is raised
by this callable the value will be removed from the list.
:return: a :class:`list` of all the values for the key.
"""
try:
rv = dict.__getitem__(self, key)
except KeyError:
return []
if type is None:
return list(rv)
result = []
for item in rv:
try:
result.append(type(item))
except ValueError:
pass
return result