#django #django-models
#django #django-модели
Вопрос:
когда я обновляю модель, изображения дублируются.
из django.db импортируйте модели из io, импортируйте BytesIO из PIL, импортируйте изображение из django.core.файлы импортируют файл
#image compression method
def compress(image):
im = Image.open(image)
im_io = BytesIO()
im.save(im_io, 'JPEG', quality=60)
new_image = File(im_io, name=image.name)
return new_image
class PhotoGallery(models.Model):
image_caption = models.CharField(max_length=50, null=True, blank=True)
image = models.ImageField(upload_to='gallery')
#calling image compression function before saving the data
def save(self, *args, **kwargs):
new_image = compress(self.image)
self.image = new_image
super().save(*args, **kwargs)
def __str__(self):
return self.image_caption
Ответ №1:
Я предполагаю, что когда вы удаляете запись изображения из базы данных, она также не удаляется с жесткого диска.
Вы можете обработать это с помощью сигналов
import os
from django.db import models
from django.dispatch import receiver
@receiver(models.signals.pre_save, sender=PhotoGallery)
def auto_delete_image_on_change(sender, instance, **kwargs):
""" Delete old image from HD on image update"""
if not instance.pk:
return False
try:
pg = PhotoGallery.objects.get(pk=instance.pk)
old_image = pg.image if pg.image else None
except PhotoGallery.DoesNotExist:
return False
new_image = instance.image
if old_image and not old_image == new_image:
if os.path.isfile(old_image.path):
os.remove(old_image.path)
@receiver(models.signals.post_delete, sender=PhotoGallery)
def auto_delete_image_on_delete(sender, instance, **kwargs):
""" Delete image from HD on image delete """
if instance.image:
if os.path.isfile(instance.image.path):
os.remove(instance.image.path)
if instance.qr_code:
if os.path.isfile(instance.qr_code.path):
os.remove(instance.qr_code.path)
Ответ №2:
Каждый раз, когда вы нажимаете save
, метод сохранения всегда запускает следующее:
#calling image compression function before saving the data
def save(self, *args, **kwargs):
new_image = compress(self.image)
self.image = new_image
super().save(*args, **kwargs)
Что означает, что при каждом нажатии он дублирует все больше и больше.
Я предлагаю проверять значение поля перед выполнением операций сжатия изображения. Но проблема в том, что вы должны использовать signals
вместо обычного сохранения. Потому что, когда вы используете метод сохранения по умолчанию / переопределенный. Состояние изменений вашего поля не записывается. Итак, для этого мы должны сделать pre_save
и post_save
сигнал для проверки, было ли изображение изменено после сжатия.
В signals.py
# ! These Variables are required to save instances.
pre_save_imageName = None # or ""
post_save_state_imageName = None # or ""
def has_image_saved(sender, instance, **kwargs):
# Refer to these variables to save pre_save and post_save states.
global pre_save_imageName, post_save_state_imageName
# We could crunch this signal for use with pre_save and post_save into one callable function.
if kwargs["action"] == "pre_save":
# You could use path or filename here. Know what getattr arguments are.
# The 3rd argument is None, the variable will be set to `None` when the function cannot find the value of the attribute.
pre_save_imageName = getattr(instance, "image", None)
if kwargs["action"] == "post_save":
if pre_save_imageName:
if pre_save_imageName != post_save_imageName:
# *do your compression here*
else:
return
В models.py
# ! Import your signals.py as well! To bind signal function of this model.
from django.db.models.signals import pre_save, post_save
class PhotoGallery(models.Model):
image_caption = models.CharField(max_length=50, null=True, blank=True)
image = models.ImageField(upload_to='gallery')
# Bind signals.
pre_save.connect(has_image_saved, sender=PhotoGallery)
post_save.connect(has_image_saved, sender=PhotoGallery)
Примечания:
- Вы могли бы удалить сжатое изображение здесь, если вам кажется, что оно было заменено.
- Если вы запутались, в сигналах
instance
эквивалентноself
. Так что замена его не будет такой уж запутанной.