Skip to content

Instantly share code, notes, and snippets.

@guillaumepiot
Last active January 22, 2024 19:19
Show Gist options
  • Star 46 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save guillaumepiot/817a70706587da3bd862835c59ef584e to your computer and use it in GitHub Desktop.
Save guillaumepiot/817a70706587da3bd862835c59ef584e to your computer and use it in GitHub Desktop.
Django Rest Framework - Image/File upload test
import os
import io
from PIL import Image
from django.core.urlresolvers import reverse
from django.conf import settings
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework.authtoken.models import Token
from rest_framework.renderers import JSONRenderer
# Custom user model based on Django Auth AbstractUser
from account.models import User
class CrewUploadPhotoTests(APITestCase):
fixtures = []
maxDiff = None
def setUp(self):
# Normal user
self.normal_user = User.objects.create(
first_name="Bob",
last_name="Green",
username="bob@green.com",
email="bob@green.com",
is_active=True,
is_staff=False)
self.normal_user.set_password('demo1234')
self.normal_user.save()
self.normal_token, created = Token.objects.get_or_create(
user=self.normal_user)
def generate_photo_file(self):
file = io.BytesIO()
image = Image.new('RGBA', size=(100, 100), color=(155, 0, 0))
image.save(file, 'png')
file.name = 'test.png'
file.seek(0)
return file
def test_upload_photo(self):
"""
Test if we can upload a photo
"""
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.normal_token.key)
url = reverse('crew-api:upload-photo', args=[self.normal_user.crew.uuid])
photo_file = self.generate_photo_file()
data = {
'photo':photo_file
}
response = self.client.post(url, data, format='multipart')
self.assertEqual(response.status_code, status.HTTP_200_OK)
@wombstrat
Copy link

Great example, thx

Copy link

ghost commented Nov 7, 2022

You are the best, when i grow up i want to be like you.

@bukowa
Copy link

bukowa commented Jan 16, 2023

Example while testing with raw serializer:

# The same file cannot be used after it has been passed to the RequestFactory, as it probably has been closed. 
# Consider using a factory to create the image.
# import factory
# image = factory.django.ImageField().evaluate(None, None, {})
upfile = BytesIO()
pilimg = Image.new('RGB', (100, 100))
pilimg.save(fp=upfile, format='PNG')
image = SimpleUploadedFile('image.png', upfile.getvalue(), content_type='image/png')

# The default 'content_type' for POST requests in Django's RequestFactory is already 
# the value of 'MULTIPART_CONTENT'.
# While using Django's RequestFactory, we can also set it explicitly, which works.
# However, when using APIRequestFactory, we have to set 'format' to 'multipart' to get the same behavior.
# Trying to set 'content_type' to the value of 'MULTIPART_CONTENT' will not work.

# from django.test.client import RequestFactory
# request = RequestFactory().post(
#     path=None,
#     data={'images': [file], 'name': "test"},
# )

request = APIRequestFactory().post(
    path=None,
    data={'images': [image], 'name': "test"},
    # mandatory for APIRequestFactory
    format='multipart',
)

# By default, DRF serializers do not have access to the request.
# But the serializer needs it to access the request.FILES.
# To simulate what DRF is doing in its request handling, update the request.POST with the request.FILES.
# This is finally passed to the serializer as request.data.
# https://github.com/encode/django-rest-framework/blob/0618fa88e1a8c2cf8a2aab29ef6de66b49e5f7ed/rest_framework/request.py#L274

class Serializer(serializers.Serializer):
    images = serializers.ListField(
        child=serializers.ImageField(),
        allow_empty=False,
    )
    name = serializers.CharField(
    required=True, validators=[lambda x: x == 'test'])


data = request.POST.copy()
data.update(request.FILES)
serializer = Serializer(data=data)
self.assertTrue(serializer.is_valid(), msg=serializer.errors)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment