Skip to main content
 首页 » 编程设计

python之将 PATCH 与 Django 图像字段和 s3 一起使用

2024年11月01日29arxive

在我当前的项目中,我将图像存储在 s3 存储桶中。 我有一个 pre_save 信号接收器,用于从 Image 类的 s3 存储桶中删除实际图像。

class Image(models.Model): 
    name = models.CharField(max_length = 255) 
    caption = models.CharField(max_length = 255) 
    image = models.ImageField(upload_to='uploads/',blank=True,null=True) 
    rent_property = models.ForeignKey(RentProperty, related_name='Images') 
    is_main_image = models.BooleanField(default=False) 
 
@receiver(models.signals.pre_save, sender=Image) 
def auto_delete_file_on_change(sender, instance, **kwargs): 
    """Deletes file from filesystem 
    when corresponding `MediaFile` object is changed. 
    """ 
    if not instance.pk: 
        return False 
 
    try: 
        old_file = Image.objects.get(pk=instance.pk).image 
    except Image.DoesNotExist: 
        return False 
 
    new_file = instance.image 
    if not old_file == new_file: 
        old_file.delete(save=False) 

我的问题是,我正在使用 django-rest-framework,我想让 PATCH 工作。但是如果我尝试修补图像描述,它会删除图像本身。我的问题是,我如何编写一个 IF 来区分天气,补丁中是否有需要更改的新图像,如果没有,什么都不做?

请您参考如下方法:

对于带有 ImageField 或 FileField 的模型,我添加了一个附加字段来存储 SHA-1 哈希字符串。我发现这很有用,原因有很多:

  • 减少同一文件的不必要传输以进行更新(您的情况)
  • 防止用户上传重复文件作为新实例
  • 在下载文件时向用户提供 SHA-1 哈希,以便他们验证下载
  • 在后端文件系统上进行数据完整性检查以验证文件没有更改

我还保存了原始文件名,以便为面向用户的查看/下载重现它。通过这种方式,后端名称对用户来说无关紧要。

这是基于您的模型的基本实现:

import hashlib 
from django.core.exceptions import ValidationError 
from django.core.files import File 
from django.db import models 
 
class Image(models.Model): 
    name = models.CharField(max_length = 255) 
    caption = models.CharField(max_length = 255) 
    image = models.ImageField(upload_to='uploads/',blank=True,null=True) 
    original_filename = models.CharField( 
        unique=False, 
        null=False, 
        blank=False, 
        editable=False, 
        max_length=256) 
    sha1 = models.CharField( 
        unique=True, 
        null=False, 
        blank=False, 
        editable=False, 
        max_length=40) 
    rent_property = models.ForeignKey(RentProperty, related_name='Images') 
    is_main_image = models.BooleanField(default=False) 
 
    def clean(self): 
        """ 
        Overriding clean to do the following: 
            - Save  original file name, since it may already exist on our side. 
            - Save SHA-1 hash and check for duplicate files. 
        """ 
 
        self.original_filename = self.image.name.split('/')[-1] 
        # get the hash 
        file_hash = hashlib.sha1(self.image.read()) 
        self.sha1 = file_hash.hexdigest() 
 
        # Check if this file has already been uploaded, 
        # if so delete the temp file and raise ValidationError 
        duplicate_hashes = Image.objects.all().exclude( 
                id=self.id).values_list('sha1', flat=True) 
        if self.sha1 in duplicate_hashes: 
            if hasattr(self.image.file, 'temporary_file_path'): 
                temp_file_path = self.image.file.temporary_file_path() 
                os.unlink(temp_file_path) 
 
            raise ValidationError( 
                "This image already exists." 
            )