0

我有以下课程:

class VideoFile(models.Model):
    media_file = models.FileField(upload_to=update_filename, null=True)

当我尝试使用以下请求向其上传大文件(从 100mb 到 2Gb)时,在上传过程之后以及在此过程中可能需要很长时间VideoFile.save()

def upload(request):
    video_file = VideoFile.objects.create(uploader=request.user.profile)
    video_file.media_file = uploaded_file
    video_file.save()

在我的 Macbook Pro Core i7、8Gb RAM 上,一个 300mb 的上传文件可能需要大约 20 秒才能运行video_file.save()

/tmp我怀疑这种延迟与从文件永久位置进行磁盘复制操作有关?我已经通过watch ls -l在目标目录上运行证明了这一点,一旦video_file.save()运行,我可以看到文件出现并在整个延迟过程中增长。

有没有办法消除这种文件传输延迟?通过将文件直接上传到目标文件名,或者只是移动原始文件而不是复制?然而,这不是整个站点的唯一上传操作,因此任何解决方案都需要本地化到此模型。

感谢您的任何建议!

更新:

只是进一步的证据来支持副本而不是移动,我可以watch lsof在上传期间看到一个/private/var/folders/...从 python 写入的文件,该文件完全映射到上传进度。上传完成后,最终文件位置会出现另一个 lsof 条目,该位置会随着时间的推移而增长。完成后,两个条目都会消失。

4

2 回答 2

1

/tmp我要提醒的是,上传到然后ing 是最佳实践的原因有很多cp,并且将大文件直接上传到其目标是一种潜在的危险操作。

但是,你问的是绝对可能的。Django 定义了上传处理程序

您可以编写自定义处理程序来自定义 Django 处理文件的方式。例如,您可以使用自定义处理程序来强制执行用户级配额、动态压缩数据、渲染进度条,甚至可以直接将数据发送到另一个存储位置,而无需将其存储在本地

于 2013-02-21T21:14:50.273 回答
1

好的,经过一番挖掘,我想出了一个解决方案。事实证明 Django 的默认存储已经尝试移动文件而不是复制,它首先测试:

hasattr(content, 'temporary_file_path')

该属性存在于作为TemporaryUploadedFile返回到上传视图的对象的类中,但是该字段本身被创建为由指定的类FileField.attr_class

因此,我决定在属性中进行子类化FieldFileFileField插槽: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某些网站可能用来处理较小的文件上传,所以我不确定我的解决方案在这方面的效果如何,但我确信它足够简单,可以检测到上传文件的类并采取相应措施。

于 2013-02-25T08:18:49.327 回答