четверг, 3 апреля 2008 г.

Фоновая загрузка файлов на сервер

Все, кто пользуется GMail замечали, что приаттаченные файлы потихоньку загружаются на сервер через несколько секунд бездействия и затем поля с именами файлов заменяются на чекбоксы.

Похожий функционал я реализовал в одном Django-проекте с помощью JQuery.
При выборе ползователем логотипа для визитки, файл логотипа прозрачно загружается на сервер, обрабатывается и затем "отдается" браузеру. и пользователь видит, что в макете логотип поменялся на выбранный им.

Реализация

После загрузки страницы запускается периодический вызов функции LoadLogotype()


<script type="'text/javascript'" src="'/appmedia/jquery.js'"></script>

<script language="JavaScript" type="text/javascript">
var previous_logo = "";

//-----------------------------------------------------------------------------
function LoadLogotype() {
var card_logo = $("#card_logo").val();

if ((card_logo != "") && (previous_logo != card_logo)) {
previous_logo = card_logo;
document.getElementById("uploadphoto").submit();
}
}
//-----------------------------------------------------------------------------
$(function() {
setInterval("LoadLogotype()", 1000);
});
</script>

Функция LoadLogotype() проверяет, выбран или изменился ли файл логотипа и, если это так, то отправляет форму "uploadphoto" на сервер.

Форма имеет параметр target="upload_frame", то-есть она не будет инициировать переход на другую страницу. Все изменения будут касаться только скрытого фрейма. После отправки формы в этом фрейме загрузиться отданный сервером результат.



<form id="uploadphoto" target="upload_frame" enctype="multipart/form-data" action="/upload_logo/" method = "post">
Логотип: <input id="card_logo" name="card_logo" type="file">
</form>



<iframe id="upload_frame" name="upload_frame" style="display:none">



Серверная функция обработки загрузки логотипа сохраняет файл в папке пользователя. Также загружаемый файл проверяется по списку alloved_files – защита от загрузки пользователем неразрешенных файлов.
Как результат функция отдает URL к файлу.

#------------------------------------------------------------------------------
def upload_logo(request):
'Handles upload of logo images'

alloved_files = ('.jpg', '.jpeg', '.png', '.gif')

id = request.session['our_id']
path = settings.MEDIA_ROOT + 'uploads/%s/' % id

if not os.path.isdir(path):
try:
os.makedirs(path)
except:
return "Error: could not create directory to upload files!"

for image_file in request.FILES:
filename = request.FILES[image_file]['filename']
name, ext = os.path.splitext(filename)
if ext not in alloved_files:
continue

if filename == '':
continue

content = request.FILES[image_file]['content']

f = open(path + filename, 'wb')
try:
f.write(content)
finally:
f.close()

content = {
"image": "/appmedia/uploads/%s/%s" % (id, filename),
}

return render_to_response("done.html", content, context_instance=RequestContext(request))

Результат рендеринга шаблона done.html попадет в невидимый IFRAME "upload_frame". Скрипт находит в родительском документе элемент "card_logotype" и заменяет URL картинки на отданный сервером.


<html>
<head>
<script language="JavaScript" type="text/javascript">
parent.document.getElementById('card_logotype').src="{{image}}"
</script>
</head>
<body>
</body>
</html>


В результате пользователь видит изменение логотипа на выбранную картинку. Весь процесс происходит без полного обновления страницы. Изменяется лишь содержимое скрытого фрейма и картинка логотипа.

Посмотреть как это работает, можно здесь: http://bicards.pythondevside.com/
Кросс-пост в Хабрахабр

Комментариев нет: