我有以下课程:
class VideoFile(models.Model):
media_file = models.FileField(upload_to=update_filename, null=True)
当我尝试使用以下请求上传大文件(从100mb到2Gb)时,在上传过程之后<{1>>可能需要很长时间过程。
VideoFile.save()
在我的Macbook Pro Core i7,8Gb内存中,一个300mb的上传文件大约需要20秒才能运行def upload(request):
video_file = VideoFile.objects.create(uploader=request.user.profile)
video_file.media_file = uploaded_file
video_file.save()
我怀疑这种延迟与从video_file.save()
到文件永久位置的磁盘复制操作有关?我已经通过在目标目录上运行/tmp
证明了这一点,并且只要watch ls -l
运行,我就可以看到文件在整个延迟期间出现并增长。
有没有办法消除此文件传输延迟?通过直接将文件上传到目标文件名或只是移动原始文件而不是复制?这不是整个站点的唯一上传操作,因此任何解决方案都需要本地化到此模型。
感谢您的任何建议!
更新:
只是进一步支持副本而不是移动的证据,我可以在上传期间video_file.save()
查看从python写的watch lsof
内的文件,该文件完全映射到上传进度。上传完成后,将显示另一个lsof条目,以查找随时间增长的最终文件位置。完成后,两个条目都会消失。
答案 0 :(得分:1)
我要提醒的是,有很多原因导致上传到/tmp
然后cp
是最佳做法,并且将大型文件直接上传到目标是一项潜在的危险操作。< / p>
但是,你所要求的绝对是可能的。 Django定义upload handlers:
您可以编写自定义处理程序来自定义Django处理文件的方式。例如,您可以使用自定义处理程序来强制执行用户级配额,动态压缩数据,渲染进度条,以及甚至直接将数据发送到另一个存储位置,而无需在本地存储。
答案 1 :(得分:1)
在经过一番挖掘之后,我想出了一个解决方案。事实证明,Django的默认存储已经尝试移动文件而不是复制,它首先测试:
hasattr(content, 'temporary_file_path')
此属性存在于类TemporaryUploadedFile
,它是返回到上载视图的对象,但字段本身是作为FileField.attr_class
所以我决定将FieldFile
和FileField
子类化并插入temporary_file_path
属性:
class VideoFieldFile(FieldFile):
_temporary_file_path = None
def temporary_file_path(self):
return self._temporary_file_path
class VideoFileField(FileField):
attr_class = VideoFieldFile
最后在视图中,在保存模型之前,我手动分配了临时路径:
video_file.media_file._temporary_file_path = uploaded_file.temporary_file_path()
现在这意味着我的1.1Gb测试文件在大约2-3秒内可用,而不是我之前看到的50秒左右。它还带来了额外的好处,即如果文件存在于不同的文件系统上,它似乎会回退到复制操作。
但是,作为旁注,我的网站没有使用某些网站可能用来处理较小文件上传的MemoryFileUploadHandler
,所以我不确定我的解决方案可能会有多好用,但我确定它很容易检测上传文件的类并采取相应的行动。