如何使用rest_framework.test.APITestCase发送多个文件

时间:2015-05-16 18:50:02

标签: python testing django-rest-framework

我正在尝试将几个文件发送到我的后端:

class AccountsImporterTestCase(APITestCase):

    def test(self):
        data = [open('accounts/importer/accounts.csv'), open('accounts/importer/apartments.csv')]
        response = self.client.post('/api/v1/accounts/import/', data, format='multipart')
        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

但是我收到了一个错误:

Error
Traceback (most recent call last):
  File "/vagrant/conjuntos/accounts/tests/cases.py", line 128, in test
    response = self.client.post('/api/v1/accounts/import/', data, format='multipart')
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 168, in post
    path, data=data, format=format, content_type=content_type, **extra)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 89, in post
    data, content_type = self._encode_data(data, format, content_type)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 64, in _encode_data
    ret = renderer.render(data)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/renderers.py", line 757, in render
    return encode_multipart(self.BOUNDARY, data)
  File "/vagrant/venv/lib/python3.4/site-packages/django/test/client.py", line 156, in encode_multipart
    for (key, value) in data.items():
AttributeError: 'list' object has no attribute 'items'

我知道我没有正确准备数据但是可以做到吗?,怎么样?谢谢!

更新:尝试@Kevin Brown解决方案

def test(self):
    data = QueryDict('', mutable=True)
    data.setlist('files', [open('accounts/importer/accounts.csv'), open('accounts/importer/apartments.csv')])
    response = self.client.post('/api/v1/accounts/import/', data, format='multipart')
    self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

得到以下信息:

Error
Traceback (most recent call last):
  File "/vagrant/conjuntos/accounts/tests/cases.py", line 130, in test
    response = self.client.post('/api/v1/accounts/import/', data, format='multipart')
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 168, in post
    path, data=data, format=format, content_type=content_type, **extra)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 89, in post
    data, content_type = self._encode_data(data, format, content_type)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/test.py", line 64, in _encode_data
    ret = renderer.render(data)
  File "/vagrant/venv/lib/python3.4/site-packages/rest_framework/renderers.py", line 757, in render
    return encode_multipart(self.BOUNDARY, data)
  File "/vagrant/venv/lib/python3.4/site-packages/django/test/client.py", line 182, in encode_multipart
    return b'\r\n'.join(lines)
TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found

2 个答案:

答案 0 :(得分:1)

您正在向视图发送文件列表,但您没有正确发送它们。当您向视图发送数据时,无论是Django视图还是DRF视图,您都应该将其作为键值对列表发送。

{
  "key": "value",
  "file": open("/path/to/file", "rb"),
}

回答你的问题...

  

是否可以这样做?

似乎无法使用相同的密钥(在测试中)上传多个文件,但可以将它们分散到多个密钥以实现相同的目标。或者,您可以将视图设置为仅处理单个文件,并具有涵盖不同测试用例的多个测试(apartments.csvaccounts.csv等。)。

您的异常正在被触发,因为您传递的是单个列表而不是字典,而Django无法正确解析它们。

通过直接形成请求字典using a QueryDict可能有一些运气,这是Django使用的表单数据的内部表示。

data = QueryDict()
data.setlist("files", [
  open('accounts/importer/accounts.csv', 'rb'),
  open('accounts/importer/apartments.csv', 'rb')
])

因为这会更接近地表示通过浏览器发送的数据。这尚未经过测试,但它是在一个密钥中发送多个非文件值的方式。

答案 1 :(得分:0)

检查这是否可以解决您的问题,因为错误明确说明数据不应该是列表

data = {"account_csv": open('accounts/importer/accounts.csv'), "apartments_csv": open('accounts/importer/apartments.csv')}

您可能会发现此链接很有用Uploading multiple files in a single request using python requests module