DEV Community

DoriDoro
DoriDoro

Posted on

Python: try - except block

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)
Enter fullscreen mode Exit fullscreen mode

Breakdown of Changes:

  1. Initial Image Verification:

    • Isolated the Image.open(self.photo) and img.verify() calls into their own try block to catch errors specific to loading and verifying the image.
  2. Image Reopen:

    • Isolated the Image.open(self.photo) again after verify() to handle potential errors specific to reopening the image.
  3. 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.

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)