我正在尝试使用Valum的Ajax Upload在我正在制作的基于Django的网站上进行文件上传.目前我正在避免表单只是因为AU在ajax请求中将上传作为整个POST数据发送.现在我有一个非常天真的方法来做到这一点:
upload = SimpleUploadedFile( filename, request.raw_post_data )
...then I loop through the chunks to write to disk...
Run Code Online (Sandbox Code Playgroud)
这适用于小文件.我已经测试了PDF,各种其他文件,以及大约20MB的Google Chrome deb软件包,它们都很棒.但是,如果我升级到类似CD或DVD的东西,它会发生可怕的轰炸.Django通常会发回Out of Memory响应.从表面上看,这是有道理的,因为SimpleUploadedFile是上传类的内存中版本.我看不到如何使用TemporaryUploadedFile,因为它没有在其构造函数中获取实际内容.作为旁注:我认为在耗尽可用的RAM后,它会转到虚拟内存,但无论如何.
所以,我的问题是,我如何让它工作?有更好的方法来读取文件吗?我尝试通过Python的IO直接读取raw_post_data(系统使用2.6.5),但是当使用二进制文件时,FileIO的ascii编码器/解码器显然会抱怨非ascii字符.我无法找到有关更改编码器/解码器的信息.
我不介意将数据传递到表单中并让Django完成选择正确的上传类的工作等等,但我无法弄清楚如何传递它,因为像
upload_form = UploadForm( request.POST, request.FILES )
Run Code Online (Sandbox Code Playgroud)
将无法工作,因为POST包含文件而不是正常的Django信息,并且FILES不存在.
正如我所说,我并不担心解决方案的方法,只是我得到了一些有用的东西!谢谢!
如果有人有兴趣,我找到了两个解决方案.
第一种是纯Python的方式,这种方式适度成功.
with BufferedReader( BytesIO( request.raw_post_data ) ) as stream:
with BufferedWriter( FileIO( "/tmp/foo.bar", "wb" ) ) as destination:
foo = stream.read( 1024 )
while foo:
destination.write( foo )
foo = stream.read( 1024 )
Run Code Online (Sandbox Code Playgroud)
它用于测试小文件(最多20MB),但是当我尝试使用ISO(~600MB)或更大的文件时失败了.我没有尝试20MB到600MB之间的任何东西,所以不确定断点在哪里.我已经复制了下面跟踪的底部,我不确定在这种情况下根本问题是什么.似乎有一个内存的困难,但我有足够的RAM +交换来保持文件三次,所以不知道为什么有一个问题.不确定使用其他形式的Python读/写或不使用缓冲区会有所帮助.
[error] [client 127.0.0.1] File "/usr/local/lib/python2.6 /dist-packages/django/core/handlers/wsgi.py", line 69, in safe_copyfileobj, referer: http://localhost/project/
[error] [client 127.0.0.1] buf = fsrc.read(min(length, size)), referer: http://localhost/project/
[error] [client 127.0.0.1] TemplateSyntaxError: Caught IOError while rendering: request data read error, referer: http://localhost/project/
Run Code Online (Sandbox Code Playgroud)
解决了我曾经抛出的所有东西,至少2GB文件,需要Django 1.3.他们为HttpRequest直接读取添加了类似文件的支持,所以我利用了它.
with BufferedWriter( FileIO( "/tmp/foo.bar", "wb" ) ) as destination:
foo = request.read( 1024 )
while foo:
destination.write( foo )
foo = request.read( 1024 )
Run Code Online (Sandbox Code Playgroud)