【问题标题】:How to get the filesize and SHA-1 digest of an uploaded file?如何获取上传文件的文件大小和 SHA-1 摘要?
【发布时间】:2012-01-22 01:09:26
【问题描述】:

我的 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 管理站点上传图像。而widthheight 属性在上传时会自动保存在数据库中,因为有特殊的ImageField 参数。

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

【问题讨论】:

    标签: python django file-upload


    【解决方案1】:

    虽然 Burhan Khalid 已经给出了答案,但我认为它仍然是谜题的部分解决方案。它仍然没有解决保存到数据库部分的问题。这是完整的解决方案,它还使用较新的 with 子句来利用 python 和 Django 的文件 context_manager(所以不需要 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)
    

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

    【讨论】:

      【解决方案2】:

      已经有一段时间了,但这样的事情应该可以工作:

      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 
      

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

      【讨论】:

      • 最好以块为单位读取文件并将这些块提供给散列函数。 hasher = hashlib.sha1() / while True: / block = f.read(1<<20) # 1MB / if block == '': break / hasher.update(block) 如果要散列的文件最终大于几 MB 并且您的应用程序因您没有限制文件大小而中断,这将避免出现问题并且有人上传了 dvd 图片或其他内容。
      • 我认为您需要在方法结束时再次调用super(Image, self).save(*args, **kwargs),以便将self.sha1self.filesize 写入数据库!
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-10
        • 2011-11-21
        相关资源
        最近更新 更多