what is the correct way to override the save method in django?

核能气质少年 提交于 2021-02-11 17:21:56

问题


I have an image model where I can upload images and I want to optimize them with pillow, I did that but there is three problems:

  1. the images doesn't get saved in the correct folder.
  2. django has a feature when there is two files with the same name django adds a random string to its name but now with two images with the same name only one gets uploaded.
  3. the original images gets uploaded too.
class Images(models.Model):
    image1 = models.ImageField(upload_to='images/%Y/', validators=[FileExtensionValidator(allowed_extensions=['png', 'jpg', 'jpeg', 'gif'])])
    image2 = models.ImageField(upload_to='images/%Y/', validators=[FileExtensionValidator(allowed_extensions=['png', 'jpg', 'jpeg', 'gif'])])

    def save(self, *args, **kwargs):
        im = Image.open(self.image1).convert('RGB')
        im2 = Image.open(self.image2).convert('RGB')
        im.save(self.image1.path,"JPEG",optimize=True,quality=75)
        im2.save(self.image2.path,"JPEG",optimize=True,quality=75)
        super(Images, self).save(*args, **kwargs) 

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

回答1:


Well, The code itself is ok, However, Images model is not good, You can create something like

I'll fix this STRUCTURE-WISE first.

class Image(models.Model):
    my_other_model = models.ForeignKey(MyOtherModel, ..., related_name='images')
    image = models.ImageField(upload_to='images/%Y/',
                              validators=[FileExtensionValidator(allowed_extensions=
                                                        ['png', 'jpg', 'jpeg', 'gif']
                                                      )])

Now, each MyOtherModel instance has .images and you can create as many images as you want instead of just 2.

Back on topic.. If this is working for you it's correct, HOWEVER, There's more than django involved, Lemme explain

    def save(self, *args, **kwargs):
        im = Image.open(self.image1).convert('RGB') # open image1, Put it in RAM
        im2 = Image.open(self.image2).convert('RGB') # open image2, Put it in RAM
        im.save(self.image1.path,"JPEG",optimize=True,quality=75) # process image1
        im2.save(self.image2.path,"JPEG",optimize=True,quality=75) # process image2
        super().save(*args, **kwargs) # easier syntax for python3

Now, I want you to compare the one above with the one below.

    def save(self, *args, **kwargs):
        im = Image.open(self.image1).convert('RGB') # open image1, Put it in RAM
        im.save(self.image1.path,"JPEG",optimize=True,quality=75) # process image1
        img.close() # remove from RAM
        im2 = Image.open(self.image2).convert('RGB') # open image2, Put it in RAM
        im2.save(self.image2.path,"JPEG",optimize=True,quality=75) # process image2
        im2.close() # remove from RAM
        super().save(*args, **kwargs) # easier syntax for python3

However, This is still wrong. Because each time it's saved, It will do all of this again, You only want to do this on the first save, On the model creation, right? If so.. Read on.

Fixing this CODE-WISE

    def save(self, *args, **kwargs):
        old_pk = self.pk # pk is created on saving, We didn't call super().save() yet!
        # so the pk should be None if this is the creation phase.

        if old_pk is None:
            im = Image.open(self.image1).convert('RGB') # open image1, Put it in RAM
            im.save(self.image1.path,"JPEG",optimize=True,quality=75) # process image1
            im1.close() # remove from RAM
            im2 = Image.open(self.image2).convert('RGB') # open image2, Put it in RAM
            im2.save(self.image2.path,"JPEG",optimize=True,quality=75) # process image2, remove from RAM
            im2.close() # remove from RAM
        super().save(*args, **kwargs) # easier syntax for python3

I've mentioned this in a question before, Reading the question is enough for you to get the point

NOTES:

  • If you want to process both images at the same time, You need to look at multiprocessing or threading or use celery.
  • FileExtensionValidator is not enough to know the file type.
  • Use a context manager when dealing with files, Search for with as expression.

The second problem is that you're not actually opening the image, open the image using Images.image1.path, This is why the original images are uploaded.

Add your MEDIA_ROOT in the question please.

For a good way of how to handle resizing images, See this



来源:https://stackoverflow.com/questions/61623638/what-is-the-correct-way-to-override-the-save-method-in-django

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!