The upload_to
的参数FileField
接受一个可调用对象,并且从该对象返回的字符串将连接到您的MEDIA_ROOT
设置以获取最终文件名(从文档 https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.FileField.upload_to):
这也可以是可调用的,例如函数,将调用该函数来获取上传路径,包括文件名。此可调用必须能够接受两个参数,并返回要传递到存储系统的 Unix 样式路径(带有正斜杠)。将传递的两个参数是:
-
instance
:定义 FileField 的模型实例。更具体地说,这是附加当前文件的特定实例。在大多数情况下,该对象尚未保存到数据库中,因此如果它使用默认的自动字段,它的主键字段可能还没有值。
-
filename
:最初赋予文件的文件名。在确定最终目的地路径时可能会或可能不会考虑这一点。
此外,当您访问model.my_file_field
,它解析为一个实例FieldFile https://docs.djangoproject.com/en/1.8/ref/models/fields/#filefield-and-fieldfile,它的作用就像一个文件。所以,你应该能够写一个upload_to
像下面这样:
def hash_upload(instance, filename):
instance.my_file.open() # make sure we're at the beginning of the file
contents = instance.my_file.read() # get the contents
fname, ext = os.path.splitext(filename)
return "{0}_{1}{2}".format(fname, hash_function(contents), ext) # assemble the filename
替换您想要使用的适当的哈希函数。根本没有必要保存到磁盘(事实上,文件通常已经上传到临时存储,或者在较小的文件仅保存在内存中的情况下)。
你可以像这样使用它:
class MyModel(models.Model):
my_file = models.FileField(upload_to=hash_upload,...)
我还没有对此进行测试,因此您可能需要查看读取整个文件的行(并且您可能只想对文件的第一个块进行哈希处理,以防止恶意用户上传大量文件并导致 DoS 攻击)。你可以得到第一个块
instance.my_file.read(instance.my_file.DEFAULT_CHUNK_SIZE)
.