使用Python请求lib不能POST文件附件和数据参数

时间:2013-10-29 12:49:51

标签: python django python-requests

我正在尝试实现一个简单的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:无法编码不是2的对象元组”。

完整的跟踪日志就是这个:

======================================================================
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') )}

但它不起作用。有没有想过如何解决这个问题?

谢谢!

1 个答案:

答案 0 :(得分: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。