Generally it is good practice to keep the try
and except
blocks as small and specific as possible. This is because it helps you identify exactly which section of your code might be causing an exception, making debugging easier and ensuring that you don't inadvertently catch exceptions that you didn't intend to handle.
Applying this principle to the save
method from article: In Django model: save an image with Pillow (PIL) library , you'll want to isolate the parts of the code that could potentially raise an exception and use try
-except
blocks specifically around those sections.
Here's a refactored save
method with more focused try
-except
blocks:
from django.core.files.base import ContentFile
from io import BytesIO
from PIL import Image, ImageOps
class Picture(models.Model):
legend = models.CharField(max_length=100)
photo = models.ImageField(
upload_to="images/",
blank=True,
null=True,
)
published = models.BooleanField(default=True)
def __str__(self):
return self.legend
def save(self, *args, **kwargs):
if self.photo:
try:
img = Image.open(self.photo)
img.verify()
except (IOError, SyntaxError) as e:
raise ValueError(f"The uploaded file is not a valid image. -- {e}")
# Reopen the image to reset the file pointer
try:
img = Image.open(self.photo)
except (IOError, SyntaxError) as e:
raise ValueError(f"The uploaded file could not be reopened as an image. -- {e}")
if img.mode in ("RGBA", "LA", "P"):
img = img.convert("RGB")
# Calculate new dimensions to maintain aspect ratio with a width of 800
new_width = 800
original_width, original_height = img.size
new_height = int((new_width / original_width) * original_height)
try:
# Resize the image
img = img.resize((new_width, new_height), Image.LANCZOS)
# Save the image as JPEG
temp_img = BytesIO()
img.save(temp_img, format="JPEG", quality=70, optimize=True)
temp_img.seek(0)
# Change file extension to .jpg
original_name, _ = self.photo.name.lower().rsplit(".", 1)
img_filename = f"{original_name}.jpg"
# Save the BytesIO object to the ImageField with the new filename
self.photo.save(img_filename, ContentFile(temp_img.read()), save=False)
except (IOError, SyntaxError) as e:
raise ValueError(f"An error occurred while processing the image. -- {e}")
super().save(*args, **kwargs)
Breakdown of Changes:
-
Initial Image Verification:
- Isolated the
Image.open(self.photo)
andimg.verify()
calls into their owntry
block to catch errors specific to loading and verifying the image.
- Isolated the
-
Image Reopen:
- Isolated the
Image.open(self.photo)
again afterverify()
to handle potential errors specific to reopening the image.
- Isolated the
-
Image Processing (Resize, Convert to JPEG):
- Isolated the resizing and conversion logic into its own
try
block to handle exceptions that could occur during image processing like resizing and saving as JPEG.
- Isolated the resizing and conversion logic into its own
By doing this, if an error occurs, it’s clearer which section of code caused the exception. This makes your error handling both more precise and more robust.
Top comments (0)