2010-11-16 2 views
11

Я пытаюсь загрузить Valum's Ajax для загрузки файлов на сайте Django , который я создаю. В настоящее время я избегаю формы просто потому, что AU отправляет загрузку как полноту данных POST в запросе ajax . Прямо сейчас у меня очень наивный подход к этому:Django 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 , он бомбит ужасно. Часто Django отправляет ответ Out of Memory . На первый взгляд это имеет смысл, так как SimpleUploadedFile - это версия для загрузки в памяти. Я не вижу, как использовать TemporaryUploadedFile, потому что он не принимает фактического содержимого в своем конструкторе . В качестве побочного примечания: я подумал бы, что после использования доступной оперативной памяти он пойдет в виртуальную память, но что угодно.

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

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

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

не будет работать, потому что POST содержит файл, а не обычный Django info и FILES не существует.

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

ответ

9

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

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

Я написал сообщение в блоге, которое показывает полную картину получения Ajax Upload для работы с Django 1.3, который включает вышеупомянутое решение. http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html –

+0

Спасибо за это @ alex-kuhl Есть ли способ подавить файловую поддержку в последняя версия Django (1.2.5)? Я боюсь, что я собираюсь атаковать адское обновление. – michela

+0

У меня не было никаких проблем с обновлением до 1.3, так что это может быть не так плохо, как вы думаете. Я никогда не пытался получить файловую поддержку в 1.2.5, поэтому я не уверен, что это можно сделать, я подозреваю, что не так легко. То, что я сделал в первом фрагменте выше, было попыткой использовать регулярные функции Python и избежать Django. Это, как я уже отмечал, работало, но не удалось загрузить файлы определенного размера. Если вы запретите большие файлы, вы можете использовать код как есть, иначе я уверен, что есть способ исправить его для работы во всех случаях. Может быть так же просто, как чтение/запись файлов с использованием разных классов. –

Смежные вопросы