如何使用django-rest-framework的测试客户端测试二进制文件上传? [英] How can I test binary file uploading with django-rest-framework's test client?

查看:134
本文介绍了如何使用django-rest-framework的测试客户端测试二进制文件上传?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Django应用程序,其视图接受要上传的文件。使用Django REST框架我将APIView进行子类化并实现这样的post()方法:

I have a Django application with a view that accepts a file to be uploaded. Using the Django REST framework I'm subclassing APIView and implementing the post() method like this:

class FileUpload(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request, *args, **kwargs):
        try:
            image = request.FILES['image']
            # Image processing here.
            return Response(status=status.HTTP_201_CREATED)
        except KeyError:
            return Response(status=status.HTTP_400_BAD_REQUEST, data={'detail' : 'Expected image.'})

现在我正在尝试编写几个单元测试,以确保需要验证,并且上传的文件被实际处理。

Now I'm trying to write a couple of unittests to ensure authentication is required and that an uploaded file is actually processed.

class TestFileUpload(APITestCase):
    def test_that_authentication_is_required(self):
        self.assertEqual(self.client.post('my_url').status_code, status.HTTP_401_UNAUTHORIZED)

    def test_file_is_accepted(self):
        self.client.force_authenticate(self.user)
        image = Image.new('RGB', (100, 100))
        tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
        image.save(tmp_file)
        with open(tmp_file.name, 'rb') as data:
            response = self.client.post('my_url', {'image': data}, format='multipart')
            self.assertEqual(status.HTTP_201_CREATED, response.status_code)

但是,当REST框架尝试对请求进行编码时,会失败$ / b
$ b

But this fails when the REST framework attempts to encode the request

Traceback (most recent call last):
  File "/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-packages/django/utils/encoding.py", line 104, in force_text
    s = six.text_type(s, encoding, errors)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 118: invalid start byte

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/vagrant/webapp/myproject/myapp/tests.py", line 31, in test_that_jpeg_image_is_accepted
    response = self.client.post('my_url', { 'image': data}, format='multipart')
  File "/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-    packages/rest_framework/test.py", line 76, in post
    return self.generic('POST', path, data, content_type, **extra)
  File "/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-packages/rest_framework/compat.py", line 470, in generic
    data = force_bytes_or_smart_bytes(data, settings.DEFAULT_CHARSET)
  File "/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-packages/django/utils/encoding.py", line 73, in smart_text
    return force_text(s, encoding, strings_only, errors)
  File "/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-packages/django/utils/encoding.py", line 116, in force_text
    raise DjangoUnicodeDecodeError(s, *e.args)
django.utils.encoding.DjangoUnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 118: invalid start byte. You passed in b'--BoUnDaRyStRiNg\r\nContent-Disposition: form-data; name="image"; filename="tmpyz2wac.jpg"\r\nContent-Type: image/jpeg\r\n\r\n\xff\xd8\xff[binary data omitted]' (<class 'bytes'>)

如何使测试客户端发送数据而不尝试解码作为UTF-8?

How can I make the test client send the data without attempting to decode it as UTF-8?

推荐答案

测试文件上传时,您应该将流对象传递到请求中,而不是数据

@ arocks


通过{'image':file}替代

Pass { 'image': file} instead

但是这并没有完全解释为什么需要它(也不符合这个问题)。对于这个具体的问题,你应该在

But that didn't full explain why it was needed (and also didn't match the question). For this specific question, you should be doing

class TestFileUpload(APITestCase):

    def test_file_is_accepted(self):
        self.client.force_authenticate(self.user)

        image = Image.new('RGB', (100, 100))

        tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
        image.save(tmp_file)

        response = self.client.post('my_url', {'image': tmp_file}, format='multipart')

       self.assertEqual(status.HTTP_201_CREATED, response.status_code)

这将匹配标准的Django请求,其中文件作为流对象传入,Django REST Framework处理它。当您传入文件数据时,Django和Django REST Framework将其解释为一个字符串,这会导致问题,因为它期待一个流。

This will match a standard Django request, where the file is passed in as a stream object, and Django REST Framework handles it. When you just pass in the file data, Django and Django REST Framework interpret it as a string, which causes issues because it is expecting a stream.

对于那些来到这里寻找另一个常见的错误,为什么文件上传不起作用,但是正常的表单数据将会:确保在创建请求时设置 format =multipart / strong>。

And for those coming here looking to another common error, why file uploads just won't work but normal form data will: make sure to set format="multipart" when creating the request.

这也提供了类似的问题,并由 @ RobinElvin 在评论中

This also gives a similar issue, and was pointed out by @RobinElvin in the comments


是因为我缺少format ='multipart'

It was because I was missing format='multipart'

这篇关于如何使用django-rest-framework的测试客户端测试二进制文件上传?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆