Search code examples
pythondjangopostdjango-rest-frameworkdjango-testing

MultiValueDictKeyError when upload an Image using Django Test


Hi I am trying to make a test case to test my upload image API. But I think I am not returning something when I pass the files for request.FILES

#models.py
class Image(models.Model):
    name = models.CharField(max_length=200)
    imagefile = models.ImageField(
        null=True,
        blank=True,
        max_length=500,
        upload_to='temp/images/')
    def __str__(self):
        return self.name

#views.py
class ImagesView(APIView):
    def post(self, request):
        print("DATA!!!", request.data)
        print("FILE!!!", request.FILES)
        params = Image(
            imagefile=request.FILES['image'])
        params.save()
        print(params)

        return Response({"status": "ok"})

#test.py
class CanalImagesApiTests(TestCase):
    fixtures = []
    def test_post_image(self):
        c = Client()
        response = c.post('/admin/login/', {'username': 'admin', 'password': 'passwrd'})
        filename = 'data/sample_image.jpg'
        name = 'sample_image.jpg'
        data = {"data": "passthis"}
        print(to_upload)
        with open(filename, 'rb') as f:
            c.post('/images/', data=data, files={"name": name, "image": f}, format='multipart')
        response = c.get('/images/')
        results = response.json()

My request.FILES is empty: <MultiValueDict: {}> and my test gets an error: django.utils.datastructures.MultiValueDictKeyError: 'image'


Solution

    • You can pass a file object inside the data dictionary.
    • files parameter is not needed. format parameter means output format, not input format.
    • You can use APITestCase instead of TestCase if you are testing Django REST Framework API. This allows you can test some method like PUT.
    from rest_framework import status
    from rest_framework.test import APITestCase
    
    
    class CanalImagesApiTests(APITestCase):
        def test_post_image(self):
            with open('data/sample_image.png', 'rb') as f:
                data = {
                    "data": "passthis",
                    "image": f,
                }
    
                response = self.client.post('/images/', data=data)
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.json(), {"status": "ok"})
    

    Test result (which is passing):

    DATA!!! <QueryDict: {'data': ['passthis'], 'image': [<InMemoryUploadedFile: sample_image.png (image/png)>]}>
    FILE!!! <MultiValueDict: {'image': [<InMemoryUploadedFile: sample_image.png (image/png)>]}>