2013-12-10 63 views
6

为了测试烧瓶中的应用程序,我得到了与文件作为附件如何使用Flask测试客户端发布多个文件?

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请求烧瓶服务器端点编码是这样的

@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( “文件[]” )正在返回一个空列表? 如何使用瓶子测试客户端发布多个文件,以便它可以在瓶子服务器端使用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?

回答

5

您发送的文件作为参数名字为file,所以你不能用t来查找它们他的名字是file[]。如果你想获得的所有命名file作为列表中的文件,你应该使用这样的:

upload_files = request.files.getlist("file") 

在另一方面,如果你真的想从file[]阅读它们,那么你需要给他们这样的:

scc.data['file[]'] = # ... 

(该file[]语法与PHP和它的使用只在客户端上,当你发送一个名为喜欢的参数到服务器,你还在使用$_FILES['file']访问它们。)

+0

谢谢。是。在浏览代码后,对于“getlist”,我昨天晚上意识到这一点,getList返回multiDict中给定的键。由于缺乏对此的理解,我使用了错误的键名。但是你确实回答了我的问题,因此会接受你的问题。还发布了我在其他答案中收集的信息。 – user2390183

2

卢卡斯已经解决了这个,只是提供这些信息,因为它可以帮助别人

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呼吁寻找一个给定的密钥在“请求”字典中。如果密钥不存在,则返回空列表。

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