Last active
January 22, 2024 19:19
-
-
Save guillaumepiot/817a70706587da3bd862835c59ef584e to your computer and use it in GitHub Desktop.
Django Rest Framework - Image/File upload test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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="[email protected]", | |
email="[email protected]", | |
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) |
Cool.
The key is generate_photo_file
and I should also make the
avatar = factory.Sequence(lambda n: f"{settings.MEDIA_ROOT}/user_avatar/fake_{n}.jpg")
correctly.
Great example, thx
You are the best, when i grow up i want to be like you.
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
.size
would give you the file size in bytes, what you are looking for here is the image dimension. For that you need an image library such as PythonPillow
to load the file and extract those values for you.https://pillow.readthedocs.io/en/stable/reference/Image.html
Hope that helps and sorry for responding a year too late 🤦♂️