1

我正在尝试实现一个简单的 Django 视图,该视图接受文件附件和其他一些参数,并在远程 API 调用上代理请求。

请注意:代理不是我的问题的重点:)

这就是我实现视图的方式:

def image_upload(request):
    token = request.POST['token']
    image_file = request.FILES.values()[0]

    files = {'file': ('myupload.txt', image_file.read())}

    client_id = request.POST['client_id']
    folder_id = request.POST['folder_id']
    advert_id = request.POST['advert_id']
    image_type = request.POST['image_type']
    crop_image = request.POST['crop_image']

    api_base_url = settings.API_BASE_URL

    file_post_data = {'client_id': client_id, 'folder_id': folder_id, 'advert_id': advert_id,
            'image_type': image_type, 'crop_image': crop_image}

    auth_header = {'Authorization': 'Token ' + token}

    r = requests.post(api_base_url + 'assets/image/upload/', 
        data = json.dumps(file_post_data), 
        headers = auth_header,
        files = files)

    return r.json()

问题是,当我测试这个视图时(我使用 Django Test Client 来做),我在“files = files)”行收到一个错误,上面写着“ ValueError: cannot encode objects that are not 2-tuples ”。

完整的跟踪日志是这样的:

======================================================================
ERROR: test_image_upload (fbx.tests.FbxTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/andrea/Documents/src/fbxapp/onboard/fbx/tests.py", line 18, in test_image_upload
    'image_type': 'A', 'crop_image': False, 'attachment': fp})
  File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 449, in post
    response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
  File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 262, in post
    return self.request(**r)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/home/andrea/Documents/src/fbxapp/onboard/fbx/views.py", line 42, in image_upload
    files = files)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 88, in post
    return request('post', url, data=data, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 324, in request
    prep = req.prepare()
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 225, in prepare
    p.prepare_body(self.data, self.files)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 385, in prepare_body
    (body, content_type) = self._encode_files(files, data)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 99, in _encode_files
    fields = to_key_val_list(data or {})
  File "/usr/local/lib/python2.7/dist-packages/requests/utils.py", line 136, in to_key_val_list
    raise ValueError('cannot encode objects that are not 2-tuples')
ValueError: cannot encode objects that are not 2-tuples

我还尝试使用它来读取文件进行快速测试:files = {'file': ('myupload.txt', open('/tmp/mytmp.txt', 'rb'))}

但它不起作用。你对如何解决这个问题有任何想法吗?

谢谢!

4

1 回答 1

3

您不能同时发布 JSON 数据,multipart/form-data这实质上就是您在这里尝试做的事情。json.dumps返回一个字符串,因此您发送的字符串看起来像

'{"client_id": 1, "folder_id": 2, "advert_id": 3, "image_type": "jpeg", "crop_image": true}'

multipart/form-data然后通过参数发送一些东西来告诉请求你想将它与请求结合使用files。这是不可能的,并且可能会引发更好的例外。

在将文件读入内存后将文件添加到 JSON 数据并使用适当的Content-Type标头发送该文件,或者将整个内容作为multipart/form-data请求发送,而不使用json.dumps并简单地将您正在创建的字典传递到data. 使用其中一种,但不能同时使用。

除此之外,您说您的异常来自仅files=files)在其上的行,但并非仅该行导致异常。该异常由恰好在该行结束的函数引发。您的例外也由此产生的事实仅仅是巧合。这是 Python 中的一个缺陷,可能在 Python 3.4 中得到修复。你应该升级,因为 3.4 会很棒而且新版本的 Django 支持 Python 3.x。

于 2013-10-29T13:34:48.820 回答