2013-12-10 60 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