我的模型字段定义如下:
file = models.FileField(storage=S3BotoStorage(bucket=blablabla), upload_to='blablabla', max_length=250)
我要做的是抓住file
中的pre_save
并压缩然后保存压缩版本。
你可能会说我应该在我的观点中这样做,但这是不可能的,因为我使用Django管理站点,我需要在整个代码中保存任何文件,无论是从视图还是Django管理站点压缩。
那么,我如何访问上传的文件,压缩并保存而不是原始文件?
感谢您的帮助。
答案 0 :(得分:1)
在pre_save信号期间看起来文件的真实名称不是最终的。
我要做的是使用 post_save信号获取最终名称,并将此名称写入另一个地方(表,提交,......)
我还会创建一个 crontab作业(可以是python程序或shell脚本),它在上传文件夹上运行并压缩所有未压缩的文件。
此作业可以根据DB Query(您更新最终名称的位置)决定要压缩哪个文件
它还可以使用“新的压缩文件名”更新一些额外的字段,并带有一个标志,表示该文件已成功擦除)
此解决方案可让您将“保管”与主码分开 它还可以使“保存”操作更快(保存时没有拉链)
答案 1 :(得分:1)
在帖子 _save信号中更容易做到这一点,如下所示:
@receiver(post_save, sender=MyModel)
def post_save_MyModel(sender, instance, *args, **kwargs):
filefield = instance.file
oldname = filefield.name #gets the "normal" file name as it was uploaded
if not oldname:
return #do nothing if file name is missing (no file was uploaded)
storage = filefield.storage
#build a unique file name for the file like: newname = '{}.zip'.format(instance.pk)
newname = <create a new filename with zip extension here>
if storage.path(newname) == storage.path(oldname):
return #do nothing if file already renamed (avoid reentrancy)
content = storage.open(oldname,"rb")
content = <zip content in-memory here>
storage.delete(newname) #delete any file with the new name eventually present already
#save the file field using the file name without directories
filefield.save(os.path.basename(newname), content, save=True) #must save model instance too!!!
content.close() #must close the original content, before deleting it!!!
storage.delete(oldname) #delete any file with the old name eventually present already
需要注意的一点是,在为上传文件创建新名称时,应该为其使用instance.pk值,以便每个实例始终只存在一个文件。 要在删除实例时删除此单个文件,可以使用以下代码:
@receiver(post_delete, sender=MyModel)
def post_delete_MyModel(sender, instance, *args, **kwargs):
filefield = instance.file
if filefield.name: #only work if file actually present
filefield.delete(save=False) #do NOT delete the instance!!!
所有这些都适用于“普通”本地文件存储。我不知道S3BotoStorage,但它应该服从Storage接口,所以它应该有所有必要的方法。
这种方法的一个问题可能是,对于S3,文件名将是由S3本身分配的某种UUID,因此可能无法为文件使用不同的名称,但也可能不需要所有...
无论如何要小心检查重新保存模型实例时被重触的重入(如果确实更改了文件名需要更新)。