Django保存覆盖ImageField处理

Rap*_*ent 1 django django-models django-admin

在我遇到这个问题之后,当我使用Django Admin时,我的models.py中仍然存在一个大问题.这是我的代码(我删除了与我的问题无关的东西):

from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image as Img
import StringIO

class Mymodel(models.Model):
        photo = models.ImageField(upload_to="photo/", blank=True, null=True)

        def save(self, *args, **kwargs):    
            width = 500
            height = 500
            size = (width,height)

            if self.photo:
                image = Img.open(StringIO.StringIO(self.photo.read()))
                (imw, imh) = image.size
                if (imw>width) or (imh>height) :
                    image.thumbnail(size, Img.ANTIALIAS)

                #If RGBA, convert transparency
                if image.mode == "RGBA":
                    image.load()
                    background = Img.new("RGB", image.size, (255, 255, 255))
                    background.paste(image, mask=image.split()[3]) #3 is alpha channel
                    image=background


                output = StringIO.StringIO()
                image.save(output, format='JPEG', quality=60)
                output.seek(0)
                self.photo = InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.photo_principale.name.split('.')[0], 'image/jpeg', output.len, None)

            try:
                this = Mymodel.objects.get(id=self.id)
                if this.photo != self.photo:
                    this.photo.delete(save=False)
            except: pass # when new photo then we do nothing, normal case 

            super(Mymodel, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

它工作正常,文件上传,调整大小并在需要时成功转换为JPEG.问题是,每次我编辑它,即使不上传新图像,它也会创建一个新图像(例如,我第一次用图像"hello.jpg"保存我的模型,然后我编辑它,它会创建一个名为"hello_1.jpg"的新图像,即使我没有上传任何内容).我认为try/except块只在编辑时才有效(所以没有新的文件上传),但显然没有.

在此先感谢您的帮助 :)

Rap*_*ent 5

最终解决方案,为我工作:

from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image as Img
import StringIO
from django.db.models.signals import post_delete
from django.dispatch import receiver

Class Mymodel(models.Model):
  photo= models.ImageField(upload_to="photo/", blank=True, null=True)

  def save(self, *args, **kwargs):
        width = 500
        height = 500
        size = (width,height)
        isSame = False
        if self.photo:
            try:
                this = Mymodel.objects.get(id=self.id)
                if this.photo==self.photo :
                    isSame= True
            except: pass # when new photo then we do nothing, normal case

            image = Img.open(StringIO.StringIO(self.photo.read()))
            (imw, imh) = image.size
            if (imw>width) or (imh>height) :
                image.thumbnail(size, Img.ANTIALIAS)

            #If RGBA, convert transparency
            if image.mode == "RGBA":
                image.load()
                background = Img.new("RGB", image.size, (255, 255, 255))
                background.paste(image, mask=image.split()[3]) # 3 is the alpha channel
                image=background


            output = StringIO.StringIO()
            image.save(output, format='JPEG', quality=60)
            output.seek(0)
            self.photo = InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.photo.name.split('.')[0], 'image/jpeg', output.len, None)

        try:
            this = Mymodel.objects.get(id=self.id)
            if this.photo==self.photo or isSame :
                self.photo=this.photo
            else :
                this.photo.delete(save=False)
        except: pass # when new photo then we do nothing, normal case 

        super(Mymodel, self).save(*args, **kwargs)

@receiver(post_delete, sender=Mymodel)
def photo_post_delete_handler(sender, **kwargs):
    instance = kwargs['instance']
    storage, path = instance.photo.storage, instance.photo.path
    if (path!='.') and (path!='/') and (path!='photo/') and (path!='photo/.'):
        storage.delete(path)
Run Code Online (Sandbox Code Playgroud)

希望它可以帮助某人;)