Django Ajax Загрузить за пределами формы - PullRequest
11 голосов
/ 16 ноября 2010

Я пытаюсь использовать Ajax Upload от Valum для загрузки файлов на Django- на основе сайта я делаю. В настоящее время я избегаю формы просто потому, что AU отправляет загрузку в виде данных POST в ajax запрос. Прямо сейчас у меня очень наивный подход к этому:

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

Это прекрасно работает ... на небольших файлах. Я тестировал с PDF, различные другие файлы, и до ~ 20 МБ Google Chrome deb пакет, и они все молодцы Однако, если я перейду к чему-то вроде CD или DVD iso это бомбы ужасно. Часто Джанго отправляет обратно нехватку памяти ответ. На первый взгляд, это имеет смысл, поскольку SimpleUploadedFile версия классов загрузки в памяти. Я не вижу, как использовать TemporaryUploadedFile, потому что он не принимает фактический контент в своем конструктор. В качестве примечания: я думаю, что после использования доступной оперативной памяти он будет идти к виртуальной памяти, но все равно.

Итак, мой вопрос: как мне заставить это работать? Есть ли способ лучше читать в файле? Я пытался напрямую читать raw_post_data через IO Python (система использует 2.6.5), но кодировщик / декодер ascii от FileIO очевидно будет жаловаться на символы не ascii при работе с бинарные файлы. Я не смог найти информацию об изменении кодер / декодер.

Я не против передать данные в форму и заставить Джанго сделать работа по выбору правильного класса загрузки и так далее, но я не могу понять, как передать это, потому что-то вроде

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

не будет работать, потому что POST содержит файл, а не обычный Информация о Джанго и ФАЙЛАХ не существует.

Как я уже сказал, меня не волнует метод решения, просто Я получаю то, что работает! Спасибо!

1 Ответ

9 голосов
/ 18 ноября 2010

Ну, я нашел два решения, если кому-то интересно.

Первый - это чисто 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 )

Он работал при тестировании небольших файлов (до 20 МБ), но не удался, когда я попробовал его с ISO (~ 600 МБ) или большими файлами.Я ничего не пробовал между 20 МБ и 600 МБ, поэтому не уверен, где находится точка останова.Я скопировал нижнюю часть трассировки ниже, я не уверен, что корень проблемы в этой ситуации.Казалось, что была проблема с памятью, но у меня было достаточно 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/

Требуется решение, которое работает со всем, что я на него брошу, по крайней мере, до 2 ГБ файловДжанго 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 ) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...