Django保存覆盖图像字段处理

Django保存覆盖图像字段处理,django,django-admin,django-models,Django,Django Admin,Django Models,在我遇到问题之后,当我使用Django管理员时,models.py中仍然存在一个大问题。这是我的代码(我删除了与我的问题无关的东西): 它的工作,文件上传,大小和转换为JPEG成功时,需要。问题是,每次我编辑它时,即使没有上传新图像,它也会创建一个新图像(例如,我第一次用图像“hello.jpg”保存我的模型,然后我编辑它,即使我没有上传任何东西,它也会创建一个名为“hello_1.jpg”的新图像)。 我认为try/except块只在编辑时有效(因此没有新文件上传),但显然不行 提前感谢您的帮

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

它的工作,文件上传,大小和转换为JPEG成功时,需要。问题是,每次我编辑它时,即使没有上传新图像,它也会创建一个新图像(例如,我第一次用图像“hello.jpg”保存我的模型,然后我编辑它,即使我没有上传任何东西,它也会创建一个名为“hello_1.jpg”的新图像)。 我认为try/except块只在编辑时有效(因此没有新文件上传),但显然不行

提前感谢您的帮助:)

试试:

if self.photo.name != '':


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

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)

希望它能帮助别人;)

这是基于Ralph的回答,我对Python3和django 2很有用

首先,您必须导入io:

from io import BytesIO
要在必要时调整大小并添加白色背景,请执行以下操作:

def resize_with_white_background(pil_image: Image.Image, desired_width, desired_height):


        img_copy = pil_image.copy()

        # get proportioned image ie (if image is 200X600 and trying to resize to 100X200
        # thumbnail will NOT do this but resize to keep the ratio so it would be 67x200 to maintain the ratio (uses the larger)
        # img_copy changed in place (does not create new image)
        img_copy.thumbnail((desired_width, desired_height), Image.ANTIALIAS)


        # create white background
        background = Image.new('RGB', (desired_width, desired_height), (255,255,255))

        pixels_to_move_left = int((background.width - img_copy.width) * 0.50)  # centered horizontally
        pixels_to_move_down = int((background.height - img_copy.height) * 0.50) # centered vertically

        # paste image into white background box argument tells where to paste
        background.paste(img_copy, box=(pixels_to_move_left, pixels_to_move_down))

        return background  # this will return the background with img_copy pasted in and will be resized to fit your desired size
要将调整大小的图像设置为,并在模型中创建一个方法,请执行以下操作:

def set_image(self, desired_width, desired_height):
    try:
        this = MyModel.objects.get(id=self.id) 
    except MyModel.DoesNotExist:
        pass
    else:
        # will not resize or set to new image (this avoids setting image every single time you edit and save
        if this.image == self.image and (self.image.width, self.image.height) == (desired_width, desired_height):
            return

    im = Image.open(BytesIO(self.image.read()))

    resized_image = resize_with_white_background(
        pil_image=im,
        desired_width=desired_width,
        desired_height=desired_height
    )

    # output (file like object)
    output = BytesIO()

    # save image into file-like object
    resized_image.save(output, format='JPEG', quality=94)

    # get size of file
    a_size = output.tell()

    # reset to beginning of file-like object
    output.seek(0)

    self.image.file = InMemoryUploadedFile(
        output,
        'ImageField',
        f"{self.image.name.split('.')[0]}.jpg",
        'image/jpeg',
        a_size,
        None
    )
重写模型的save()方法,并在调用Super()之前调用set_image()方法。save(*args,**kwargs)方法


尝试记录
self.photo
,以便在编辑时查看其值。然后,您可以测试它,并绕过保存。
def resize_with_white_background(pil_image: Image.Image, desired_width, desired_height):


        img_copy = pil_image.copy()

        # get proportioned image ie (if image is 200X600 and trying to resize to 100X200
        # thumbnail will NOT do this but resize to keep the ratio so it would be 67x200 to maintain the ratio (uses the larger)
        # img_copy changed in place (does not create new image)
        img_copy.thumbnail((desired_width, desired_height), Image.ANTIALIAS)


        # create white background
        background = Image.new('RGB', (desired_width, desired_height), (255,255,255))

        pixels_to_move_left = int((background.width - img_copy.width) * 0.50)  # centered horizontally
        pixels_to_move_down = int((background.height - img_copy.height) * 0.50) # centered vertically

        # paste image into white background box argument tells where to paste
        background.paste(img_copy, box=(pixels_to_move_left, pixels_to_move_down))

        return background  # this will return the background with img_copy pasted in and will be resized to fit your desired size
def set_image(self, desired_width, desired_height):
    try:
        this = MyModel.objects.get(id=self.id) 
    except MyModel.DoesNotExist:
        pass
    else:
        # will not resize or set to new image (this avoids setting image every single time you edit and save
        if this.image == self.image and (self.image.width, self.image.height) == (desired_width, desired_height):
            return

    im = Image.open(BytesIO(self.image.read()))

    resized_image = resize_with_white_background(
        pil_image=im,
        desired_width=desired_width,
        desired_height=desired_height
    )

    # output (file like object)
    output = BytesIO()

    # save image into file-like object
    resized_image.save(output, format='JPEG', quality=94)

    # get size of file
    a_size = output.tell()

    # reset to beginning of file-like object
    output.seek(0)

    self.image.file = InMemoryUploadedFile(
        output,
        'ImageField',
        f"{self.image.name.split('.')[0]}.jpg",
        'image/jpeg',
        a_size,
        None
    )
def save(self, *args, **kwargs):
    self.set_image(
        desired_width=100,  # can be whatever you want
        desired_height=200
    )

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