Django 如何在使用 ImageField 保存模型时检查用户是否上传了图像文件?

标签 django django-models

我正在寻找一种在保存 ImageField 时调整大小、压缩和优化上传图像的方法。

class Image(models.Model):
    name = models.CharField(max_length=254, blank=True)
    caption = models.TextField(max_length=1000, blank=True)
    height = models.IntegerField()
    width = models.IntegerField()
    image = models.ImageField(upload_to='', height_field='height', width_field='width', storage=S3MediaStorage())

我的第一个想法是覆盖模型的 save() 并在那里实现这个逻辑,但我不希望在用户不更新时再次运行调整大小/压缩/优化图像文件(即,如果他只更新现有对象的 namecaption 并保存它)。

  1. 什么是检查新图像文件何时上传到 ImageField 的正确方法,而不是当用户仅更改模型中的另一个字段时,例如。用户更新了 caption 但其他一切保持原样?

  2. 如何在代码中访问上传的图像文件? IE。包含可以传递给 Pillow 的实际图像文件的变量是什么?

编辑:这在 the suspected duplicate 中是独一无二的.我不是在问这个领域是否已经改变,因为那总是会导致误报。我问用户是否上传了一个图像文件,我会立即更改(调整大小/优化/压缩),所以如果用户立即下载他上传的图像,他会发现它有一个不同的二进制文件和随机生成的文件名,并且因此,比较文件名或二进制文件不是确定用户是否上传不同图像的有效方法。

最佳答案

您的模型可以使用不同的名称。

不过,您可以尝试通过 post_save 信号 ( https://docs.djangoproject.com/en/1.9/ref/signals/#post-save ) 操纵图像

from PIL import Image
from django.db.models.signals import post_save

@receiver(post_save, sender=Image)
def crop_image(sender, instance, **kwargs):
    img = instance.image
    original = Image.open(img.src.path)
    # ... your code here...

编辑:抱歉。稍微跳了枪。您的实际问题之一是如果图像相同则不要对其进行操作。您可以像这样在 save() 上执行此操作(未测试):

def save(self, **kwargs):
    try:
        related_img = Image.objects.get(id=self.id)
        if related_img.image != self.image:
            crop_me(self.image)
    except Image.DoesNotExist:
        # object doesn't exist. Passing...
        pass

    return super(Image, self).save(**kwargs)

def crop_me(img):
    original_img = Image.open(img.src.path)
    # ... your code here...

编辑 2:如果名称更改,您可以将原始文件名保存在辅助字段中

class Image(models.Model):
    image = models.ImageField(upload_to='', height_field='height', width_field='width', storage=S3MediaStorage())

    __original_image_filename = None

    def __init__(self, *args, **kwargs):
        super(Image, self).__init__(*args, **kwargs)
        self.__original_image_filename = self.image.name

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        if self.image.name != self.__original_image_filename:
        # name changed - do something here

        super(Image, self).save(force_insert, force_update, *args, **kwargs)
        self.__original_image_filename = self.image.name

我正在即时修改另一个答案,因此可能会出现一两个错误。请查看the original answer .关于这个问题还有其他方法可以帮助您。

关于Django 如何在使用 ImageField 保存模型时检查用户是否上传了图像文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36133243/

相关文章:

Django fixture 加载很慢

python - Django ORM 魔法。错误还是功能?

django - 无法使用 Bitnami Django 堆栈连接到 Postgres 数据库

python - django: blog() 缺少 1 个必需的位置参数: 'blog_id'

python - Django 外键的模型字段未正确更新

管理中需要具有默认空字符串的 django charfield

python - Django DecimalField 在保存时生成 "quantize result has too many digits for current context"错误

django - 我可以在 Django 模型中封装其他类以获得更具可读性的代码吗?

django - 获取模型外键名称和值?

python - 使用Pycharm调试django meet错误