Пытается протестировать Django ModelForm, но тесты не выполняются. Передавая необходимые данные, но все равно отображается «Поле изображения обязательно», а тесты показывают недопустимую форму.
models.py
# models.py
import sys
from PIL import Image
from io import BytesIO
from django.contrib.auth.models import User
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db import models
from django.utils.translation import ugettext as _
class ProfileImage(models.Model):
user = models.OneToOneField(User, verbose_name=_("user"), on_delete=models.CASCADE)
image = models.ImageField(upload_to="profile")
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
if not self.id:
uploaded_image = Image.open(self.image)
rgb_image = uploaded_image.convert("RGB")
output = BytesIO()
image_resized = rgb_image.resize((300, 300))
image_resized.save(output, format="JPEG", quality=100)
output.seek(0)
self.image = InMemoryUploadedFile(
output, "ImageField", "{}.jpg".format(self.image.name.split('.')[0]),
"image/jpeg", sys.getsizeof(output), None
)
super().save(*args, **kwargs)
forms.py
# forms.py
from PIL import Image
from django import forms
from django.forms.utils import ErrorList
from django.utils.translation import ugettext as _
from .models import (
ProfileImage,
)
class ProfileImageForm(forms.ModelForm):
class Meta:
model = ProfileImage
fields = ["image"]
def clean(self):
image = self.cleaned_data.get("image")
if image:
image = Image.open(image)
width, height = image.size
image_format = image.format
if image_format not in ("PNG", "JPEG", "MPO"):
msg = _("Unsupported image type. Please upload a *png or *jpg image.")
self._errors["image"] = ErrorList([msg])
del image
if width < 300 or height < 300:
msg = _("Image is too small! Please upload image of size 300px x 300px or More.")
self._errors["image"] = ErrorList([msg])
del image
return self.cleaned_data
test_forms.py
# test_forms.py
import os
import tempfile
from mixer.backend.django import mixer
import numpy
from PIL import Image
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from base.models import (
ProfileImage
)
from base.forms import (
ProfileImageForm,
)
# utils functions
def get_test_image(height=100, width=100):
"""
Generate image for test purpose
Args:
height(int): image height
width(int): image width
Returns:
image(str): image path
"""
image = tempfile.NamedTemporaryFile(suffix=".png", dir=settings.MEDIA_ROOT, delete=True).name
imarray = numpy.random.rand(height, width, 3) * 255
im = Image.fromarray(imarray.astype("uint8")).convert("RGBA")
im.save(image)
return image
def delete_test_image(image):
"""
Delete image generated for test purpose
Args:
image(str): image path
Returns:
"""
if os.path.exists(image):
os.remove(image)
class TestFormData(TestCase):
def setUp(self):
self.standard_profile_test_image = get_test_image(300, 300)
# 1st way, Fails
def test_image_form_valid_1(self):
image_path = self.standard_profile_test_image
profile_img_instance = mixer.blend(ProfileImage, image=image_path)
image = profile_img_instance.image
form_data = {"image": image}
form = ProfileImageForm(form_data)
self.assertTrue(form.is_valid())
delete_test_image(profile_img_instance.image.path)
# 2nd way, Fails
def test_image_form_valid_2(self):
image_path = self.standard_profile_test_image
with open(image_path, "rb") as f:
file_data = f.read()
file_name = f.name
form_data = {"image": SimpleUploadedFile(file_name, file_data)}
form = ProfileImageForm(data=form_data)
self.assertTrue(form.is_valid())
def tearDown(self):
delete_test_image(self.standard_profile_test_image)
Когда я запустил эти два теста, оба из них выдавали ошибки: form is invalid
Форма показывает the image field is required
даже при том, что я передал необходимые данные.
>>> form
>>> <ProfileImageForm bound=True, valid=False, fields=(image)>
>>> form.errors
>>> {'image': ['This field is required.']}
>>> form.non_field_errors()
>>> []