如何使用django rest framework的测试客户端测试二进制文件上传?

我有一个Django应用程序,它的视图接受要上传的文件。使用Django REST框架,我正在对APIView进行子类化,并实现post()方法,如下所示:

类文件上载(APIView):
权限\类=(已验证,)
def post(自我、请求、*args、**kwargs):
尝试:
image=request.FILES['image']
#这里是图像处理。
返回响应(状态=status.HTTP\u 201\u已创建)
除KeyError外:
返回响应(status=status.HTTP_400_BAD_请求,数据={'detail':'Expected image.})

现在,我正在尝试编写几个单元测试,以确保需要进行身份验证,并且上传的文件实际上得到了处理

类TestFileUpload(APITestCase):
def测试是否需要身份验证(自我):
self.assertEqual(self.client.post('my_url')).status\u代码,status.HTTP\u 401\u未经授权)
接受def测试文件(自我):
self.client.force\u身份验证(self.user)
image=image.new('RGB',(100100))
tmp_file=tempfile.NamedTemporaryFile(后缀='.jpg')
image.save(tmp_文件)
以open(tmp_file.name,'rb')作为数据:
response=self.client.post('my_url',{'image':data},format='multipart')
self.assertEqual(status.HTTP\u 201\u已创建,response.status\u代码)

但是,当REST框架尝试对请求进行编码时,这将失败

回溯(最近一次呼叫最后一次):
文件“/home/vagrant/.virtualenvs/myapp/lib/python3.3/site packages/django/utils/encoding.py”,第104行,强制文本
s=6。文本类型(s、编码、错误)
UnicodeDecodeError:“utf-8”编解码器无法解码位置118处的字节0xff:无效的开始字节
在处理上述异常期间,发生了另一个异常:
回溯(最近一次呼叫最后一次):
文件“/home/vagrant/webapp/myproject/myapp/tests.py”,测试中第31行,即接受jpeg图像
response=self.client.post('my_url',{'image':data},format='multipart')
文件“/home/vagrant/.virtualenvs/myapp/lib/python3.3/site-packages/rest\u framework/test.py”,第76行,在post中
返回self.generic('POST',路径,数据,内容类型,**额外)
文件“/home/vagrant/.virtualenvs/myapp/lib/python3.3/site packages/rest\u framework/compat.py”,第470行,通用格式
数据=强制字节或智能字节(数据、设置、默认字符集)
智能文本中的文件“/home/vagrant/.virtualenvs/myapp/lib/python3.3/site packages/django/utils/encoding.py”,第73行
返回强制文本(s、编码、仅字符串、错误)
文件“/home/vagrant/.virtualenvs/myapp/lib/python3.3/site packages/django/utils/encoding.py”,第116行,强制文本
提升数据删除错误(s,*e.args)
django.utils.encoding.DjangoUnicodeDecodeError:“utf-8”编解码器无法解码第118位的字节0xff:无效的开始字节。您传入了b'--BoUnDaRyStRiNg\r\n内容配置:表单数据;name=“image”;filename=“tmpyz2wac.jpg”\r\n内容类型:image/jpeg\r\n\r\n\xff\xd8\xff[二进制数据省略](<类“字节”>)

如何让测试客户端发送数据而不尝试将其解码为UTF-8

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

@arocks在评论中指出了这一点

改为传递{‘image’:文件}

但这并不能完全解释为什么需要它(也与问题不符)。对于这个特定的问题,您应该

来自PIL导入图像的


类TestFileUpload(APITestCase):
接受def测试文件(自我):
self.client.force\u身份验证(self.user)
image=image.new('RGB',(100100))
tmp_file=tempfile.NamedTemporaryFile(后缀='.jpg')
image.save(tmp_文件)
tmp_文件.seek(0)
response=self.client.post('my_url',{'image':tmp_file},format='multipart')
self.assertEqual(status.HTTP\u 201\u已创建,response.status\u代码)

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

对于那些来这里查看另一个常见错误的人来说,为什么文件上传无法正常工作,而普通表单数据将正常工作:确保在创建请求时设置format=“multipart”

这也带来了类似的问题,@RobinElvin在评论中指出了这一点

这是因为我缺少格式=’multipart’

发表评论