Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework - Unit test image file upload

I am trying to unit test my file uploading REST API. I found online some code generating the image with Pillow but it can't be serialized.

This is my code for generating the image :

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

Then I try to upload this image fille :

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

And I get the following error:

<ContentFile: Raw content> is not JSON serializable

How can I transform the Pillow image so it's serializable?

like image 739
Elbbard Avatar asked Nov 16 '16 20:11

Elbbard


1 Answers

I wouldn't recommend submitting your data as JSON in this case, as it complicates the issue. Just make a POST request with the parameters and files you want to submit. Django REST Framework will handle it just fine without you needing to serialise it as JSON.

I wrote a test for uploading a file to an API endpoint a while back which looked like this:

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)

In this case, I used the tempfile module to store an image generated using Pillow. The with syntax used in the example allows you to pass the content of the file in the request body comparatively easily.

Based on this, something like this should work for your use case:

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

Incidentally, depending on your use case it might be more convenient to accept the image data as a base 64 encoded string.

like image 98
Matthew Daly Avatar answered Nov 06 '22 19:11

Matthew Daly