Иван Сагалаев рассказал как обстоят дело с загрузкой файлов через веб-формы в Django. Я решил посмотреть какая ситуация у TurboGears.
В целом все ОК, если бы не один момент. TurboGears использует FormEncode для валидации форм. FormEncode содержит FieldStorageUploadConverter для обработки полей типа FILE, вот только оно не работает. ;-) Похоже, что это просто баг - надо бы зафайлить отчет об ошибке разработчикам.
В итоге мне пришлось написать свой валидатор. Другое отличие - TurboGears не имеет специальной логики для хранения картинок/файлов. Для простоты я решил сохранить обложку в БД. Для полноты картины прилагаю и весь остальной код, готовый TG-проект можно взять здесь.
Детально комментировать мне лень, но если будет интерес можно будет написать несколько более детальных постов о TurboGears.
Так форма описывается:
class FileUploadConverter(validators.FancyValidator):
def to_python(self, value, state=None):
if isinstance(value, cgi.FieldStorage):
if value.filename:
return value
raise validators.Invalid('invalid', value, state)
else:
return value
album_form = widgets.TableForm(name='album',
fields=[
widgets.TextField('title', validator=validators.UnicodeString()),
widgets.FileField('cover', validator=FileUploadConverter(not_empty=False))
])
А так - отображается (плюс показываются существующие записи):
@turbogears.expose(template='tff.templates.welcome')
def index(self):
albums = Album.select()
return dict(albums=albums, form=album_form)
Это представление (Kid шаблон):
Existing albums
${album.title} (no cover)
Add new album
${form.display(action=’do_add_album’)}
Так происходит валидация и добавление нового альбома:
@turbogears.error_handler(index)
@turbogears.validate(form=album_form)
@turbogears.expose()
def do_add_album(self, title=None, cover=None):
if cover is not None:
cover = cover.value
# cover.filename contains original filename and cover.type - content-type
a = Album(title=title, cover=cover)
turbogears.flash('Album has been added')
turbogears.redirect('/')
Ну а это - вспомогательный метод для отображения картинки на лету:
@turbogears.expose()
@turbogears.validate(validators={'id':validators.Int()})
def get_cover(self, tg_errors=None, id=None):
if not tg_errors:
try:
album = Album.get(id)
content_type = 'image/gif'
cherrypy.response.headers['Content-Type'] = content_type
return album.cover
except sqlobject.SQLObjectNotFound:
pass
return ''
Это собственно модель:
class Album(SQLObject):
title = UnicodeCol(length=90)
cover = BLOBCol()
Источники:
developers.org.ua