Шло время, появился javascript, CGI, но файлополя были все также эгоистичны. Потом появился флеш, html5, ситуация начала меняться, но… Файловое поле имеет ту-же самую суть — файл, а не файлы! Хотя есть множество обходных методов…
Итак, коллеги, как вы уже догадались, я желаю поделиться с вами еще одним «велосипедом». И я буду безумно рад, если он сделает чью-то жизнь чуточку легче. Но перед тем как продолжить, я не могу не поблагодарить создателей такого чудного инструмента, как Plupload — кросбраузерного мультиаплоадера файлов.
asv_files
Итак, знакомьтесь, asv_files — это кастомное поле для формы (в дальнейшем и для модели), позволяющее грузить в себя N файлов. Не только поле, но и некоторая обвязка, позволяющая пережить уже загруженным файлам такое события как невалидность формы и отправку ее
Создатели plupload обещают кроссбраузерность и у меня нет основания им не верить. По крайней мере в IE, Opere, FireFox'e и Хроме поле ведет себя как ему и положено.
Идеология и основные постулаты
Итак, основные постулаты, которыми я руководствовался:
- Никаких красивостей. Я не настолько хороший телепат чтобы попасть в Ваш дизайн. Темплейт прост и доступен для модификации, главное не потерять имена классов. Текстовые-же сообщения вообще переопределимы через settings.py либо через наследование класса, если для различных файловых полей в форме нужны различные сообщения.
- На одной web-странице может быть N форм, в каждой форме, в свою очередь, может быть M файловых полей. Форма может пытаться сабмититься бесконечное число раз.
- Если мы можем работать через html5 — через него и работаем, если нет — в нашем распоряжении flash, silverlight, эгоистичный html4.
- Если есть незагруженные файлы, то форму сабмитить нельзя (отключаемо).
- Используем class-based views для большей гибкости и возможности отнаследоваться.
- Кириллические имена файлов, имена файлов с пробелами и спецсимволами — это зло, следовательно их необходимо транслитирировать и нормализовывать. Но имя файла на пользовательской стороне часто бывает важной информацией, по-этому не теряем его, а храним до поры до времени.
- файлы могут храниться не только локально, по-этому используем имеющийся в Django механизм Файл-сториджей. Будет активно пилиться интеграция с dropbox, google-drive и яндекс-диском.
- django.staticfiles — это позитивно и в девелопменте и в деплое.
- manage.py должен содержать команды для управления файлами.
Инсталляция
Сложность инсталляции поражает воображение:
$ pip install asv_files
При этом asv_files притащит за собой немного зависимостей, одна из которых (asv_media) содержит и jQuery и plupload и способна отдать их через staticfiles.
Затем вам придется подключить приложения asv_files, asv_media и django.contrib.sites в settings.py
INSTALLED_APPS = ( ..... 'django.contrib.sites', ..... 'asv_media', 'asv_files', ..... )
Создать при помощи manage.py необходимые модели:
$ python manage.py syncdb
И пригласить в urls.py
from django.conf.urls import patterns, include, url urlpatterns = patterns('', ..... url('AnY_YoUr_LiKe_PaTh/', include('asv_files.urls', namespace='asv_files')), .....
Подключать RPC-ответчик можно по любому URLу, важно сохранить неизменным вышеуказанный namespace.
Как использовать
Работа с формами в Django практически не зависит от того используете ли вы классические views или перешли на class-based. Суть одна:
описать форму:
from django import forms from asv_files.fields import CTfilesFormField class TestForm(forms.Form): #..... files = CTfilesFormField() #.....
использовать ее во вьюхе:
def TestView(request, ...): obj = Articles.objects.get(.........) if request.method == 'POST': form = TestForm(request.POST) if form.is_valid(): # ..... files = form.cleaned_data['files'] for i in files.get_files(): print('file {frn} saved as {fn} ({fp}) and have ID:{id}'.format( frn = i.get_realname(), fn = i.get_filename(), fp = i.get_filepath(), id = i.fileid, )) i.attach_to(obj) # attach to OBJ through ContentTypes #i.delete() # remove file from database and storage files.delete() # remove session and her files from database and storage else: form = TestForm() return render(request, 'template.html', { 'form': form, }
не забыв правильно подключить в темплейте медиафайлы:
{% extends "base.html" %} {% block add_to_head %} {{form.media}} {% endblock %} {% block wp %} <hr> <form method="POST" action="{% url demo:form1 %}">{% csrf_token %} <table>{{ form.as_table }}</table> <input type="submit"> <input type="reset"> </form> {% endblock %}
блок «add_to_head», естественно, должен существовать в Вашем базовом темплейте.
Управление через manage.py
В manage.py доступна команда uploads, с помощью которой можно управлять сесиями загрузок и временными файлами (то есть файлами которые загрузили, но форму не засабмитили, либо засабмитили, но программист забыл стереть файлы в обработчике сабмита формы):
$ ./manage.py uploads --help Usage: ./manage.py uploads [options] <sess_ID or filename> Managament for upload files and sessions Options: --sessions list unclosed upload sessions and it's files, if exist --realname display real (user's) file name near file name --no-files, --nofiles do not display information about files --older=XX use only sessions older than XX hours --only-uuids, --onlyuuids show only session's UUIDs --remove remove upload session and her files
Итак, есть две основных команды:
и$ ./manage.py uploads --sessions
$ ./manage.py uploads --remove sessID-1 sessID-2 ... sessID-N
Первая показывает незавершенные сессии загрузок, их файлы, и прочую связанную с ними информацию.
Вторая — удалаяет из DB перечисленные сессии и соответствующие им файлы.
Ключи к команде uploads --sessions:
- --realname — показывать не только имя файла, под которым он сохранен, но и имя файла под которым его пытался загрузить пользователь
- --no-files — не показывать информацию о файлах. Только идентификаторы сессий
- --only-uuids — вывести только ID-ы сессий через пробел в одну длинную строчку. Удобно использовать для последующего удаления.
- --older=XX — показать только сессии, с возрастом (датой создания) более, чем XX часов. Часы можно указывать как целым, дак и десятичным числом (=0.25 — четверть часа)
И в заключении хочу… сказать...
Исходные тексты asv_files лежат тут.
Документация, написанная, как всегда, на скорую руку — рядом.
Небольшая демка (для разнообразия используется CBV), иллюстрирующая работу двух полей рядом — на противоположном конце континента.
А потрясающая документация на CBV — ближе, чем можно подумать…
С удовольствием приму критику, багфиксы, предложения.
Спасибо за внимание.
UPD: Opera починена, Safari грузит, но добавляет пофайлово через html4
Поддерживаемые браузеры: InternetExplorer 7+, Firefox, Chrome, Opera, Safari
