问题
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:
- the images doesn't get saved in the correct folder.
- 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.
- 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