如何获取上传文件的文件大小和SHA-1摘要?
我在我的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
(宽度)和height
(高度)这两个属性会自动保存在数据库里,这是因为使用了特别的ImageField
参数。
不过,我还想让它自动计算上传文件的大小和SHA-1摘要,并把这些属性也保存下来。我该怎么做呢?
3 个回答
我不太确定你是否能自动完成这个操作。不过,ImageField
其实也是一种FileField
,所以你可以打开这个文件,然后用hashlib.sha1
来计算它的校验和。为了计算校验和,你需要读取文件,这样你也可以同时获取文件的大小。
我已经有一段时间没用Django的ORM了,但我记得可以写一个方法,这个方法会在模型实例被保存到存储或者从存储读取时被调用。这个地方就是进行计算的好时机。
虽然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试图读取一个已经关闭的文件,结果它以为这个文件还是打开的。super()也是最后一个命令,用来把我们更新的所有内容保存到数据库中(在之前的最佳答案中,这一步被遗漏了,你可能需要再次调用save()才能真正保存这些细节)。
过了一段时间,但像这样的代码应该可以正常工作:
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。