Skip to content

Instantly share code, notes, and snippets.

@jacoor
Last active December 11, 2024 08:47
Show Gist options
  • Save jacoor/1dfbd40497d4125f6888384bf61c845a to your computer and use it in GitHub Desktop.
Save jacoor/1dfbd40497d4125f6888384bf61c845a to your computer and use it in GitHub Desktop.
Django image validator example
avatar = models.ImageField(
upload_to=user_avatar_path,
null=True,
blank=True,
default=None,
validators=[
FileExtensionValidator(allowed_extensions=["jpg", "jpeg", "png"]),
validate_image_file, # Reusable image validation
],
)
import pytest
from django.core.exceptions import ValidationError
from io import BytesIO
from PIL import Image
from users.validators import validate_image_file # Replace 'your_app' with your app name
def create_test_image(format="JPEG", size=(100, 100), color=(255, 0, 0)):
"""
Helper function to create an in-memory test image.
"""
img = Image.new("RGB", size, color)
image_io = BytesIO()
img.save(image_io, format=format)
image_io.seek(0)
return image_io
@pytest.mark.parametrize("image_format", ["JPEG", "PNG"])
def test_valid_image_formats(image_format):
"""
Test that valid image formats pass the validation.
"""
image_file = create_test_image(format=image_format)
try:
validate_image_file(image_file)
except ValidationError:
pytest.fail(f"Validation failed for valid {image_format} image.")
def test_invalid_image_format():
"""
Test that an invalid image format raises a ValidationError.
"""
image_file = BytesIO(b"not-a-real-image")
with pytest.raises(ValidationError, match="Uploaded file is not a valid image."):
validate_image_file(image_file)
def test_image_with_unsupported_format():
"""
Test that an image with an unsupported format raises a ValidationError.
"""
image_file = create_test_image(format="BMP")
with pytest.raises(ValidationError, match="Only JPEG and PNG image formats are supported."):
validate_image_file(image_file)
def test_image_too_large_dimensions():
"""
Test that an image exceeding the maximum dimensions raises a ValidationError.
"""
max_width, max_height = 1920, 1080
image_file = create_test_image(size=(max_width + 1, max_height + 1))
with pytest.raises(ValidationError) as excinfo:
validate_image_file(image_file)
# Assert the error message matches the new, consistent message
assert "Image is too large." in excinfo.value.messages[0]
def test_valid_image_dimensions():
"""
Test that an image within the valid dimensions passes the validation.
"""
max_width, max_height = 1920, 1080
image_file = create_test_image(size=(max_width, max_height))
try:
validate_image_file(image_file)
except ValidationError:
pytest.fail("Validation failed for an image within valid dimensions.")
def test_corrupted_image_file():
"""
Test that a corrupted image file raises a ValidationError.
"""
image_file = create_test_image()
# Corrupt the image file by truncating its content
corrupted_image_file = BytesIO(image_file.read()[:10])
with pytest.raises(ValidationError, match="Uploaded file is not a valid image."):
validate_image_file(corrupted_image_file)
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from PIL import Image
import os
def validate_image_file(image_file):
"""
Validator to ensure the uploaded file is a valid image.
"""
from PIL import Image
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
try:
img = Image.open(image_file)
img.verify()
except (IOError, SyntaxError):
raise ValidationError(_("Uploaded file is not a valid image."))
img = Image.open(image_file) # Required after .verify()
allowed_formats = ["JPEG", "PNG"]
if img.format not in allowed_formats:
raise ValidationError(_("Only JPEG and PNG image formats are supported."))
max_width, max_height = 1920, 1080
width, height = img.size
if width > max_width or height > max_height:
raise ValidationError(
_(f"Image is too large. Maximum resolution is {max_width}x{max_height} pixels.")
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment