Python 如何更改预保存信号中的models.FileField?
我有一个定义如下的模型字段:Python 如何更改预保存信号中的models.FileField?,python,django,Python,Django,我有一个定义如下的模型字段: file = models.FileField(storage=S3BotoStorage(bucket=blablabla), upload_to='blablabla', max_length=250) 我想做的是在pre_save中抓取文件,压缩它,然后保存压缩版本 你可能会说我应该在我的视图中这样做,但这是不可能的,因为我使用的是Django管理站点,我需要在整个代码中保存任何文件,无论是来自视图还是Django管理站点 那么,我怎样才能访问上传的文件、压
file = models.FileField(storage=S3BotoStorage(bucket=blablabla), upload_to='blablabla', max_length=250)
我想做的是在pre_save
中抓取文件
,压缩它,然后保存压缩版本
你可能会说我应该在我的视图中这样做,但这是不可能的,因为我使用的是Django管理站点,我需要在整个代码中保存任何文件,无论是来自视图还是Django管理站点
那么,我怎样才能访问上传的文件、压缩文件并将其保存而不是原始文件?在预保存信号期间,文件的真实名称似乎不是最终名称 我要做的是使用post_save信号获取最终名称,并将该名称写入另一个位置(表、文件等) 我还将创建一个crontab作业(可以是python程序或shell脚本),该作业将在上载文件夹上运行,并压缩所有未压缩的文件。
此作业可以根据DB查询(您在其中更新了最终名称)决定压缩哪个文件
它还可以使用“新压缩文件名”更新一些额外字段,并带有一个标志,表明文件已成功压缩)
- 创建另一个模型来描述文件上载。
在模型中,每个文件都应至少包含以下字段
“文件名:字符串”,“压缩文件名:字符串”,“压缩:布尔” - 在为当前模型进行后期保存期间,更新此新模型的“文件名”
- 设置一个cron选项卡,从新模型中读取“was_zipped==none”的所有条目
这个Crontab作业将压缩所有这些文件,并在写入新文件后更新模型李>
它还将使“保存”操作更快(保存过程中无压缩)在post\u保存信号中执行此操作更容易,如下所示:
@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
所有这些都适用于“正常”本地文件存储。我不知道S3BOtograge,但是它应该服从存储接口,所以它应该有所有必要的方法
此方法的一个问题可能是,对于S3,文件名将是S3本身指定的某种UUID,因此可能无法为文件使用不同的名称,但也可能根本不需要它
无论如何,要小心检查模型实例重新保存时出现的重新进入状态(如果文件名确实更改,则需要更新文件名)。感谢cron概念。我用过。
@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!!!