如何获取上传文件的filesize和SHA-1摘要?

时间:2012-01-22 01:09:26

标签: python django file-upload

我的Django应用程序中有这个模型:

class Image(models.Model):
    image_file = models.ImageField(
        upload_to='images/', 
        width_field='width',
        height_field='height'
    )
    width = models.PositiveIntegerField(
        blank = True, null = True,
        editable = False
    )
    height = models.PositiveIntegerField(
        blank = True, null = True,
        editable = False
    )

    sha1 = models.CharField(max_length=32, blank=True, editable=False)
    filesize = models.PositiveIntegerField(blank=True, null=True, editable=False)

我现在可以通过Django管理站点上传图片了。由于特殊的width参数,heightImageField属性会在上传时自动保存在数据库中。

但我也希望自动计算上传文件的尺寸 SHA-1 摘要,并保存这些属性。我该怎么做?

3 个答案:

答案 0 :(得分:3)

已经有一段时间了,但这样的事情应该有效:

import hashlib
class Image(models.Model):
#...
    def save(self, *args, **kwargs):
        super(Image, self).save(*args, **kwargs)
        f = self.image_file.open('rb')
        hash = hashlib.sha1()
        if f.multiple_chunks():
           for chunk in f.chunks():
              hash.update(chunk)
        else:    
              hash.update(f.read())
        f.close()
        self.sha1 =  hash.hexdigest()
        self.filesize = self.image_file.size 

编辑:   添加了关于大块阅读的建议。默认块大小为64KB。

答案 1 :(得分:1)

我不确定你是否可以自动完成。但ImageField也是FileField,因此您始终可以使用hashlib.sha1打开文件并计算校验和。您必须读取文件以计算校验和,以便您可以同时嗅探大小。

我使用Django的ORM已经有一段时间了,但我相信有一种方法可以编写一个方法,只要将模型实例保存到底层存储或从底层存储中读取,就会调用该方法。这是进行计算的好地方。

答案 2 :(得分:0)

尽管Burhan Khalid给出了答案,但我认为它仍是难题的部分解决方案。它仍然不能解决保存到数据库部分的问题。这是完整的解决方案,该解决方案还使用更新的with子句来利用python和Django的文件context_manager(因此不需要no和file.close(),它会自动发生):

import hashlib
class Image(models.Model):
#...
def save(self, *args, **kwargs):
    with self.image_file.open('rb') as f:
        hash = hashlib.sha1()
        if f.multiple_chunks():
        for chunk in f.chunks():
            hash.update(chunk)
        else:    
            hash.update(f.read())
        self.sha1 =  hash.hexdigest()
        self.filesize = self.image_file.size 
        super(Image, self).save(*args, **kwargs)

请注意,在with子句中调用了super()。这一点很重要,否则您将得到一个错误:ValueError: I/O operation on closed file.,因为Django尝试读取已关闭的文件,并在其关闭时以其为打开状态。这也是将我们已更新的所有内容保存到数据库的最后一条命令(这是上一个最佳答案所遗留的位置,您很可能必须再次调用save()才能真正保存这些详细信息)