表单外的 Django Ajax 上传

Posted

技术标签:

【中文标题】表单外的 Django Ajax 上传【英文标题】:Django Ajax Upload Outside of a Form 【发布时间】:2011-05-10 21:45:31 【问题描述】:

我正在尝试使用 Valum 的 Ajax Upload 在 Django 上进行文件上传- 我正在制作的基于网站。目前我正在避免使用表格仅仅是因为 AU 将上传作为 ajax 中的全部 POST 数据发送 要求。现在我有一个非常天真的方法来做到这一点:

upload = SimpleUploadedFile( filename, request.raw_post_data )
...then I loop through the chunks to write to disk...

这对小文件很有用。我已经用 PDF 进行了测试,各种 其他文件,以及最多约 20MB 的 Google Chrome deb 包,它们 一切都很好。但是,如果我升级到 CD 或 DVD iso 之类的东西 它爆炸得很厉害。 Django经常发回内存不足 回复。从表面上看,这是有道理的,因为 SimpleUploadedFile 是 上传类的内存版本。我看不到如何使用 TemporaryUploadedFile,因为它不包含实际内容 构造函数。作为旁注:我想在用完之后 可用的 RAM 它会转到虚拟内存,但无论如何。

所以,我的问题是,我该如何让它发挥作用?有没有更好的办法 读入文件?我尝试通过直接读取 raw_post_data Python 的 IO(系统使用 2.6.5)但 FileIO 的 ascii 编码器/解码器 使用时显然会抱怨非ASCII字符 二进制文件。我一直无法找到有关更改的信息 编码器/解码器。

我不介意将数据传递到表单中并让 Django 执行 选择正确的上传类等工作,但我不知道 知道如何通过它,因为像

upload_form = UploadForm( request.POST, request.FILES )

将不起作用,因为 POST 包含文件而不是正常的 Django 信息和文件不存在。

正如我所说,我不担心解决方案的方法,只是担心 我得到了一些有用的东西!谢谢!

【问题讨论】:

【参考方案1】:

如果有人感兴趣,我找到了两个解决方案。

第一种方法是使用纯 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 )

它可以测试小文件(最大 20MB),但当我尝试使用 ISO(~600MB)或更大的文件时失败了。我没有尝试 20MB 和 600MB 之间的任何东西,所以不确定断点在哪里。我已经复制了下面跟踪的底部,我不确定在这种情况下根本问题是什么。似乎有内存问题,但我有足够的 RAM+swap 来保存文件三倍,所以不知道为什么会出现问题。不确定使用其他形式的 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/

适用于我提供的所有内容的解决方案(至少 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 ) 

【讨论】:

我写了一篇博文,展示了让 Ajax Upload 与 Django 1.3 一起工作的全貌,其中包括上述解决方案。 kuhlit.blogspot.com/2010/12/… 感谢@alex-kuhl 有什么办法可以将类似文件的支持融入到最新版本的 Django (1.2.5) 中?我担心我会遇到依赖地狱升级。 我升级到 1.3 没有任何问题,所以它可能没有你想象的那么糟糕。我实际上从未尝试在 1.2.5 中获得类似文件的支持,所以我不确定这是否可以做到,我怀疑这并不容易。我在上面的第一个 sn-p 中所做的是尝试使用常规 Python 功能并避免使用 Django。正如我所指出的,它确实有效,但对于超过一定大小的文件失败了。如果您不允许大文件,那么您可以按原样使用代码,否则我相信有一种方法可以修复它以适用于所有情况。可以像使用不同的类进行文件读/写一样简单。

以上是关于表单外的 Django Ajax 上传的主要内容,如果未能解决你的问题,请参考以下文章

Django框架 之 Form表单和Ajax上传文件

django 基于form表单上传文件和基于ajax上传文件

python测试开发django-178.ajax实现form表单文件上传

django中通过文件和Ajax来上传文件

如何使用 Django 和 AJAX 显示上传的图像

使用ajax上传时缺少Django文件