【问题标题】:using PATCH with a Django image field and s3使用带有 Django 图像字段和 s3 的 PATCH
【发布时间】:2014-05-20 10:54:05
【问题描述】:

在我当前的项目中,我将图像存储在 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,或者补丁中是否有需要更改的新图像,如果没有,则什么都不做?

【问题讨论】:

  • 我通常在数据文件的模型字段中保存一个 SHA-1 哈希,并检查它是否发生变化。这对你有用吗?
  • 你真是个天才。它工作得很好。由于它每次更新时都会获得一个新的随机唯一名称,所以我只检查那是否已更改,如果没有,我保留旧图像。您能否以答案的形式写下您的评论,以便我接受它,并在未来对其他人有所帮助?
  • 太好了,很高兴它对你有用。我添加了一个更详细的答案。

标签: python django amazon-s3 django-rest-framework http-patch


【解决方案1】:

对于具有 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."
            )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 2014-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多