【问题标题】:Django Rest Framework - Unit test image file uploadDjango Rest Framework - 单元测试图像文件上传
【发布时间】:2017-03-31 05:02:22
【问题描述】:

我正在尝试对我的文件上传 REST API 进行单元测试。我在网上找到了一些使用 Pillow 生成图像的代码,但无法序列化。

这是我生成图像的代码:

image = Image.new('RGBA', size=(50, 50), color=(155, 0, 0))
file = BytesIO(image.tobytes())
file.name = 'test.png'
file.seek(0)

然后我尝试上传这张图片:

return self.client.post("/api/images/", data=json.dumps({
     "image": file,
     "item": 1
}), content_type="application/json", format='multipart')

我收到以下错误:

<ContentFile: Raw content> is not JSON serializable

如何转换 Pillow 图像以使其可序列化?

【问题讨论】:

  • 您是否尝试过省略json.dumps 电话?在我的 django 项目中,我只是使用测试客户端将数据作为字典发布。

标签: django rest django-rest-framework


【解决方案1】:

在这种情况下,我不建议您以 JSON 格式提交您的数据,因为这会使问题复杂化。只需使用您要提交的参数和文件发出POST 请求。 Django REST Framework 可以很好地处理它,而无需您将其序列化为 JSON。

不久前我写了一个将文件上传到 API 端点的测试,看起来像这样:

def test_post_photo(self):
    """
    Test trying to add a photo
    """
    # Create an album
    album = AlbumFactory(owner=self.user)

    # Log user in
    self.client.login(username=self.user.username, password='password')

    # Create image
    image = Image.new('RGB', (100, 100))
    tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
    image.save(tmp_file)

    # Send data
    with open(tmp_file.name, 'rb') as data:
        response = self.client.post(reverse('photo-list'), {'album': 'http://testserver/api/albums/' + album.pk, 'image': data}, format='multipart')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

在这种情况下,我使用了tempfile 模块来存储使用 Pillow 生成的图像。示例中使用的with 语法使您可以比较容易地在请求正文中传递文件的内容。

基于此,这样的事情应该适用于您的用例:

image = Image.new('RGBA', size=(50, 50), color=(155, 0, 0))
file = tempfile.NamedTemporaryFile(suffix='.png')
image.save(file)

with open(file.name, 'rb') as data:
    return self.client.post("/api/images/", {"image": data, "item": 1}, format='multipart')

顺便说一句,根据您的用例,将图像数据作为 base 64 编码字符串接受可能更方便。

【讨论】:

  • 我实现了这个解决方案,它在 Windows 中工作了一段时间,但后者得到了错误PermissionError: [Errno 13] Permission denied: 'C:... 可能它需要一些额外的功能,如stackoverflow.com/q/130763/2343488 的答案中所述
  • 感谢您提供此解决方案。一个提示:我在一个接一个地运行多个测试时非常忙碌。我总是收到类似OSError: cannot identify image file "/tmp/tmpci3voa1h" 的错误。解决方案:您需要在运行一个测试后对文件对象调用 seek(0),例如data.seek(0)
  • Image 模块来自哪里?
  • @RudolfOlah PIL 或枕头
【解决方案2】:

您将文件转换为字节,这不是 JSON 可序列化的。

在不知道您的 API 期望接收什么的情况下,我不得不猜测您必须将 file 编码为字符串:"image": file.decode('utf-8')

虽然对于单元测试图像上传到 REST API 的一般问题有很多解决方案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 2014-10-16
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 2019-09-01
    相关资源
    最近更新 更多