Загрузка файлов в Django. FileField & upload_to. 3
На момент выхода версии 1.0 Django, одним из самых значительных изменений стал механизм загрузки (upload) и хранения (storage) файлов. Загрузка файлов без FileField в модели базы данных конечно очень редкий случай, поэтому начнем именно с одного из обязательных параметров FileField — upload_to.
Главная инновация — это гибкая возможность настройки этого самого upload_to. Раньше можно было только передавать строку
с кодированными strftime параметрами. Тем самым можно было разбивать
загруженные файлы по директориям, создаваемыми по дате, типа uploads/mp3/2008-12/uploaded.mp3. Сейчас параметром
upload_to может быть и callable, т.е. к примеру функция, которая должна возвращать полный путь с именем файла, куда
будет сохраняться загруженный файл. Функция должна принимать два параметра: instance и filename.
- instance — это экземпляр объекта модели, которой и принадлежит поле с типом FileField.
- filename — юникодное имя файла.
Эта функция будет запускаться перед сохранением в базу, поэтому если объект новый (вы не редактируете существующий объект, а создаете новый), то поле pk/id будет пустым и соотвественные Django сигналы еще не выполнены.
Думаю, что с примером кода все будет наиболее хорошо понятно.
Итак функция-callback, которую мы будем использовать в upload_path:
def make_upload_path(instance, filename):
"""Generates upload path for FileField"""
return u"uploads/%s/%s" % (instance.category.slug, filename)
Теперь пример модели с FileField:
class Upload(models.Model):
user = models.ForeignKey(User)
file = models.FileField(upload_to=make_upload_path)
category = models.ForeignKey(Category)
uploaded_date = models.DateTimeField(auto_now_add=True)
Все просто. Можно использовать множество параметров вашей модели для создания директорий
и упорядочивания файлов в них. И самое главное upload_to — самый простой способ
закачивания файлов с русскими (и другими юникодными) именами. Т.к. по-умолчанию
Django заменяет их на символ подчеркивания, что приводит к появлению файлов типа __________.jpg.
Если вы сделаете самую простую функцию с вовращением вида return u"uploads/mypath/%s" % (filename),
то получите русские имена файлов после закачки.
Официальная документация Django по FileField.
Django signals по-новому 1
На пути к 1.0 релизу Django претерпевал немало радикальных изменений. Одно из них рефакторинг системы сигналов.

Если вы первый раз читаете и не в курсе «что это такое и с чем его едят», то скажу в двух словах. Это система реагирования на события приложения. Любой JavaScript или прикладной UI программист хорошо знаком с системой событий (event) — клик мышкой, нажатие горячей клавиши и т.п. Для программистов серверной части веба все выглядит немного по другому. Есть HTTP-запрос и есть его обработчик, анализируется как правило URL на предмет «кому отправлять запрос». Но на самом деле это та же система сигналов-событий, только узкопрофилированная под обработку HTTP-запросов.
Оказывается серверная часть веб-приложения тоже может, и я уверен, просто должна генерировать намного больший спектр сигналов, чем просто обработку URL и данных запроса. С чем успешно и справляется Django. Теперь немного прозы. Какие же события может ловить Django «из-коробки».
pre_init— перед запуском метода-конструктора__init__()модели;post_init— после выполнения метода__init__()модели;pre_save— перед сохранением экземпляра модели в базу;post_save— после успешного сохранения экземпляра модели в базу;pre_delete,post_delete— перед и после удаления экземпляра модели из базы;post_syncdb— генерируется админкой Django после установки нового приложения (INSTALLED_APPS);request_started,request_finished,got_request_exception— генерируются при обработке HTTP-запросов;template_rendered— генерируется только в режиме тестирования приложения.
Итак сигналы *_init, _*save, *_delete и post_syncdb генерируются системой моделей Django и их можно импортировать из django.db.models.signals.
Сигналы обработки HTTP-запросов из django.core.signals. И тестовый template_rendered из django.test.signals.
А теперь реальный пример, как повесить обработчик на событие-сигнал сохранения модели. В нашем случае будет требоваться определить тип mime закачанного файла перед его сохранением в базу.
Код модели:
class MimeType(models.Model):
"""
Mime Types table
"""
name = models.CharField(max_length=200)
slug = models.SlugField()
def __unicode__(self):
return self.name
class Item(models.Model):
"""
Main file
"""
name = models.CharField(max_length=200)
slug = models.SlugField()
file = models.FileField(upload_to='files', blank=True)
mime = models.ForeignKey(MimeType, blank=True, null=True)
upload_date = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
def set_mime(self, mime):
obj, created = MimeType.objects.get_or_create(name=mime, slug=slugify(mime))
self.mime = obj
Посмотрите на метод set_mime модели Item. Он создает новый объект MimeType или использует если он уже создан.
При этом не сохраняя модель Item. Теперь я пишу функцию-callback, которая будет вызываться по событию сохранения модели Item.
import mimetypes
import os.path
# init mime types dict
mimetypes.init()
def add_mime_type(instance, **kwargs):
"""
Adding mime-type to uploaded file (for future use).
Would be called on post-save.
"""
if not hasattr(instance, 'mime') or not hasattr(instance, 'file'):
raise Exception("Object %s does not have 'mime' attribute! Can't set mime-type!" % instance)
if instance.file:
extension = os.path.splitext(instance.file.path)[1].lower()
instance.set_mime(mimetypes.types_map[extension])
Итак, функция-callback add_mime_type принимает параметр instance, который является экземпляром модели, сгенерировавшим сигнал (в нашем случае модели Item). Вторым параметром принимает словарь (dictionary). Кстати, это и есть один из моментов обратной несовместимости. После рефакторинга каждая функция-callback должна принимать параметр **kwargs.
Теперь третий самый простой шаг — связывание модели с сигналом. В самом конце файла моделей добавилась строчка:
models.signals.pre_save.connect(add_mime_type, sender=Item)
Теперь перед каждым сохранением объектов Item, будет выполняться проверка и установка Mime-типа.
Кстати, я советую если у вас больше одного сигнала, выносите их в отдельный файл signals.py или можно по-старинке писать в файле моделей (что ИМХО иногда мешает чтению кода).
Почитать про сигналы можно еще в официальной доке: Django Signals и Django Built-in signal reference. Почитать про рефаторинг можно на странице Backwards Incompatible Changes и в соответствующем коммите 8223.
Александр Кошелев тоже немного раньше написал по теме, статья «А вы поймали новые сигналы?» с хорошим примером создания абстрактного сигнала.
«На сегодня все. Вопросы в студию» :-)
Django 1.0
Не буду говорить насколько релиз важен или наоборот нет. Я в целом разделаю точку зрения Ивана. Но думаю, что как раз релиз является отличным поводом написать много новых заметок, статей и примеров кода по новым и переделанным фичам.
Так что ждите в скором будущем новых статей по Django тематике. Думаю осветить подробно:
- эффективное создание форм;
- кастомизация django admin интерфейса;
- трюки с FileField и аплоадом в общем;
- сигналы в django.
Django + Spawning! 3
Вышла новая переписанная версия Spawning — WSGI сервера. Главное достоинство это non-blocking IO, т.е. большие возможности по масштабируемости (scaling).
Spawning is a wsgi server which supports multiple processes, multiple threads, non-blocking HTTP io, and automatic graceful upgrading of code.
Это очередной способ запуска django и других python-приложений для веб. Пример команды для запуска django процесса:
spawn --factory=spawning.django_factory.config_factory settings --port 9090 -s 4 -t 100
Пример для запуска приложений через paste (например Pylons используют paste для деплоя):
spawn --factory=spawning.paste_factory.config_factory development.ini
Если захотелось поставить и попробовать:
sudo easy_install Spawning
Почитайте еще обзор Эрика на английском.
Update: как ни странно товарищ Александр aka piranha практически одновременно со мной написал статью как раз про деплой через WSGI. Так что моя заметка «пролетает как фанера над Парижем», ибо мягко говоря Spawing не самый быстрый вариант :-) Читайте — Amazon byteflow: WSGI серверы кратко и юзайте fapws2.
Django newforms-admin в trunk 1
Есть! Наконец-то замержили в trunk django newforms-admin — Changeset 7967. Учтите, что после апдейта нужно будет переписывать код для работы админки. Но новость однозначно отличная! Много новых фич и ближе к релизу 1.0
Как говорят «там»: stay tuned! Будут примеры по настройке новой админки.
А товарищу Brian Rosner респект за удачный мерж.
File uploads в django 3
ДА! Это наконец-то случилось! Иван может петь победоносную песню, он так долго боролся за решение этого вопроса!
By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold the entire contents of the upload in memory. This means that saving the file involves only a read from memory and a write to disk and thus is very fast. However, if an uploaded file is too large, Django will write the uploaded file to a temporary file stored in your system’s temporary directory.
Полная дока по новому аплоаду — Django | File Uploads | Django Documentation.
Линкотека №3. «Как ляжет карта». 3
Как я вчера обещал, начинаю активнее добавлять контент :-)
Третий выпуск «Линкотеки» посвящен картографии и Google maps в частности. К слову, тема вообще очень интересная и популярная. Я, честно говоря, недооценивал ее увлекательность и предлагаемые возможности, пока не столкнулся с ней в одном их своих новых проектов. В блогах все чаще можно услышать новомодную фразу гео-тегирование, а на разных социальных сервисах все чаще предлагают привязать какую-то виртуальную информацию к географическим координатам. Так что будте готовы наваять свой код, когда столкнетесь с необходимостью работать с гео-данными.
Mapstraction — JavaScript библиотека для работы с многими картографическими сервисами через единый API.
Modest Maps — Библиотека для работы с картографическими сервисами на ActionScript (v2 / v3) и Python.
cfis — Блог Charlie Savage, разработчика GIS систем. Много информации общего характера для понимания тонкостей картографического софта, плюс примеры кода.
Google maps. Snap to Polyline (example) — Пример JavaScript кода для привязки курсора к полигонам и полилиниям в Google maps.
Google maps. Resizable Polygons (example) — Пример JavaScript кода для создания полигонов с возможностью ресайзинга в Google maps.
Take Control of Your Maps — Отличный обзор картографического (GIS) софта для построения веб-приложений от «A List Apart».
jMaps jQuery plugin — Плагин к jQuery для базовой работы с Google maps.
GeoDjango — Отдельная ветка django, отлично заточенная на работу с гео-данными (GIS). Фич очень много, советую хотя бы ради интереса ознакомится. Главным я считаю полную интеграция с PostgreSQL PostGIS на уровне ORM.
django-geo — В отличии от GeoDjango, облегченный вариант для интеграции гео-данных в ваш django-проект.
На этом, пожалуй остановлюсь. Если тема GIS и работы с гео-данными интересна, дайте знать. Если нет, то я не буду закидывать вас неинтересным контентом. Просто есть мысли в следующих постах привести некоторые куски кода по теме с объяснениями.

Подкаст о веб-разработке 36
Сегодня важное событие у меня. Я наконец-то смог выродить подкаст о веб-разработке, который планировал оч давно записать. Даже не только планировал, но и пробывал. Итак, это моя третья попытка — более-менее удачная. Не могу сказать что я на 100% доволен результатом, но как говориться «первый блин можно и простить» :-)
Для меня намного важнее узнать ваше мнение, уважаемые читатели! На сколько вам был бы полезен вообще подкаст о веб-разработке. И о каких темах вы бы хотели услышать выпуски в будующем. Любые ваши комментарии (желательно конструктивные) будут мотивировать меня для дальнейшей записи. А так как я не диктор и не работал никогда на радио, дается мне сие записывание нелегко... Так что хотелось бы знать интересно ли будет что-то подобное для вас. Жду фидбека, а пока качайте 10 минутное mp3 весом в 14Мб :-)
Отдельный фид для подкаста скоро будет.

Update: сделал еще копию подкаста с битрейтом 128 на 10Мб
Две модели в newforms 10
На днях нужно было за короткое время решить одну несложную и довольно типичную задачу на django — построение формы профайла пользователя. Я не стал искать в закладках ссылки на старые известные how-to от мэтров-джангистов :-), а попробовал посмотреть что же нового и интересного у нас имеется в последней версии django (trunk).
Итак, модель была приготовлена заранее, вопрос больше касался построения формы (через newforms) пользовательского профайла. Итак, модель.
class UserProfile(models.Model):
user = models.ForeignKey(User, verbose_name=_('user'), unique=True, related_name="profile")
country = models.ForeignKey(Country, verbose_name=_('country'), blank=True, null=True)
city = models.CharField(verbose_name=_('city'), max_length=30, blank=True, null=True)
post_zip = models.CharField(verbose_name=_('post zip'), max_length=10, blank=True)
address = models.CharField(verbose_name=_('address'), max_length=250, blank=True)
Обратите внимание, что профайл ссылается на модель User с unique=True. Это в принципе самый простой и работающий вариант расширения модели пользователя в django. Можно смело использовать для объекта User метод profile.get(). Например:
from django.contrib.auth.models import User
u = User.objects.get(username='test')
profile = u.profile.get()
Теперь для моделей User и UserProfile необходимо построить единую форму. Для каждой отдельной модели сделать это не проблема. А вот сделать «два в одном» не так просто. Итак, по порядку:
Новенькое — широко используемые функции form_for_model и form_for_instance оказывается уже не актуальны. Они работают, но есть более новый и интересный метод получения формы для модели — ModelForm.
В отличии от форм полученных через form_for_model и form_for_instance, формы от ModelForm можно наследовать (а вот это очень интересно в нашем случае!!!).
Поэтому, как только эти два пункта появились в моей голове, я сразу же открыл Python-консоль и начал экспериментировать с кодом. Не уверен на 100%, что мое решение максимально красивое, но тем не менее оно вполне простое и аккуратное (особенно если учесть, что времени на «подумать» особо не было)...
Итак кусочек моего forms.py ниже.
from django.newforms.models import ModelForm
from django.contrib.auth.models import User
from django import newforms as forms
from profile.models import UserProfile
class ProfileForm(ModelForm):
class Meta:
model = UserProfile
fields=('country', 'city', 'post_zip', 'address')
class ProfileFormFull(ProfileForm):
def __init__(self, *args, **kwargs):
super(ProfileFormFull, self).__init__(*args, **kwargs)
self.fields['first_name'] = User._meta.get_field('first_name').formfield()
self.fields['last_name'] = User._meta.get_field('last_name').formfield()
def save_user_data(self):
if self.instance:
user = self.instance.user
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
return user.save()
else:
raise instance.DoesNotExist
Теперь мои комментарии к коду (что я делаю):
- Создаю форму ProfileForm из моей модели UserProfile.
- Наследую от ProfileForm новую форму ProfileFormFull, которую буду расширять для возможности редактирования двух моделей (User и UserProfile) в одной форме.
- Суть расширения в добавлении двух полей из модели User (first_name и last_name) и метода save_user_data который эти поля сохраняет в модель User.
- Остальные поля из модели UserProfile обрабатываются автоматически созданным методом save.
- При сохранении формы нужно вызывать два метода — save и save_user_data. Я специально оставил эту возможность для моего случая. Но вы можете сделать сохранение save_user_data внутри save, расширив его.
Как выглядит код, который работает с этой формой:
@login_required
@render_to('profile/main.html')
def profile_save(request):
if request.method == 'GET':
return HttpResponseRedirect(reverse('profile.views.profile_page'))
profile, created = UserProfile.objects.get_or_create(user=request.user)
form = ProfileFormFull(data=request.POST, instance=profile)
if form.is_valid():
form.save()
form.save_user_data()
request.user.message_set.create(message="Your profile details saved.")
return HttpResponseRedirect(reverse('profile.views.profile_page'))
else:
return {'profile': profile, 'profile_form': form, 'user': request.user}
На этом пожалуй откланиваюсь. Был бы очень рад любым конструктивным замечаниям и вопросам в комментариях. Хотелось бы унифицировать кусок кода с формой (forms.py) и может вынести в отдельный сниппет.
PS: обязательно почитайте документацию по ModelForm, интересно :-)
Загрузка всех моделей в django shell автоматом 2
Наткнулся на интересную заметку. Как автоматизировать загрузку всех моделей из INSTALLED_APPS при запуске django python shell (manage.py shell).
from django.db.models.loading import get_models
for m in get_models():
exec "from %s import %s" % (m.__module__, m.__name__)Оказывается очень удобно! :-)
Оригинал — Peter Sheats’ Blog » Blog Archive » Autoloading Your Django Models
Линкотека №1 9
Решил сменить свою del.icio.us ленту в сайдбаре на более-менее регулярный постинг интересных ссылок.
А вот место в сайдбаре собираюсь заполнить блогроллом. Так что если хотите попасть в список — напишите мне на имейл или в комментарии свой сайт/блог. Добавляю на условии, что вы ставите на меня обратный линк.
Итак интересное, что я «нарыл» на просторах интернета за последние пару недель.
- StaticGenerator for Django — ссылка дня! очень полезный проект для django-разработчиков, может генерировать статический html вариант сайта из моделей, пользуясь методом
get_absolute_url. Самое главное, что через сигналы он может автоматом обновлять html-страницы при изменении/добавлении объектов (т.е. буквально данных в базе). - Evaluation of web based WYSIWYG-editors, test result 2007 — обзор онлайновых WYSIWYG редакторов (javascript и один на java), с него набрел на один интересный редактор (следующая ссылка).
- WYMeditor - web-based XHTML editor — простой интересный онлайн редактор, без возможности upload/insert images, но зато более семантичный и наглядный для тех, кто знает HTML.
- WYMstyle и css-boilerplate — css frameworks, хороши для веб проектов, когда у вас еще нет дизайна веб-сайта/веб-приложения, но вам нужно более-менее симпатично показать контент и функционал. Облегчают работу тем, кто не любит долгой возни с версткой.
- swfobject 2 — новая переработанная версия (на данный момент rc1) javascript библиотеки для включения в страницу flash/flex роликов или приложений. Кто еще не пробывал — советую, намного удобнее, чем писать кроссбраузерные теги и делать ручные проверки нужной версии flash. Еще можно почитать блог разработчиков — SWFFix Dev Blog.
- transdb — неплохая библиотека для локализации конента в django. Добавляет специальные многоязыковые текстовые поля в модель, что облегчает работу с базой и хорошо интегрируется с существующей системой i18n в django.
- PyAMF — Реализация на Python поддержки протокола обмена данными AMF (от Adobe) для клиент-серверного взаимодействия. Используется во flash и других проектах Adobe. Данные по этому протоколу передаются в бинарном виде, что более-продуктивно с точки зрения потребления траффика, автоматизирована сериализация/десериализация данных как на стороне сервера, так и клиента.
Не изобретая велосипед 5
Хотел поделиться списком django-проектов, которые могут быть очень полезны при старте любого нового проекта. Чтобы, как говориться, «не изобретать велосипед».
Из того, что пробывал лично я, советую:
- sorl-thumbnail – для генерации thumbnail картинок для ImageField, очень удобно, может делать crop, изменение качества для jpg, подробнее смотрите на сайте проекта (все параметры задаются прямо через темплейттаг, так что верстальщики не будут задалбывать каждый раз когда нужно поменять размер картинки на фронтенде);
- django-registration – для автоматизации регистрации юзеров (проверка имейла итд), скорее всего будете затачивать под себя, так что годиться но с напильником;
- django-tagging – неплохая реализация тегирования для джанги, но требует доработки в плане оптимизации запросов к базе;
- django-template-utils – можно выцепить полезный код или использовать «как есть» при работе с темплейтами, полезные темплейттаги;
Из того, что не пробывал, но советую пробывать читателям:
- django-voting – система рейтинга для контента (работает для юбой модели);
- django-evolution – новый проект для тракинга изменений схемы базы (моделей); сам не тестил, но отзывы хорошие;
- django-atompub – для генерации atom-фидов (feeds), намного гибче стандартного джанговского, очень хорошие отзывы;
- django-rest-interface – для создания ReST API, возможно для работы с ajax;
- typogrify – для обработки вводимого/выводимого текста (правильные кавычки, тире итд); актуально только для англоязычных проектов, наша типографика отличается (читайте Лебедева);
- django-localdates – для корректной локализации дат; интересно как работает с русскими датами, кто может протестировать?
Отдельно. Готовые к бою приложения:
- ByteFlow – блогодвижок, разработка моего товарища, оч советую (есть скрипт миграции с wordpress).
- feedjack – приложение, feed агрегатор на джанге. Полезно для коммунити-сайтов.
- webthumb-api – генерация превьюшек реальных сайтов (передаешь ссылку получаешь картинку).
- django-diario – блогодвижок, не смотрел код, кто пробывал или попробует – напишите комментарий о своем впечатлении.
- django-photologue – фотогалерея, тоже сам не пробывал, но судя по описанию довольно «продвинутое» приложение (кто попробывал – отпишитесь).
- snapboard – готовый движок форума, опять же не пробывал, если есть впечатления – напишите.
django: как создать html сообщение
Вот по следам недавних дискуссий в django-users пишу заметку как создавать имейлы с аттачами и html-ом.
Есть патчи в тикете #1541 для интеграции в саму джангу или можно воспользоваться примерами кода отсюда и отсюда.
django.vim
Обновился vim-овский файл синтаксиса для django. смотреть на vim.org
Добавили:- новую систему комментариев {# greeting #}
- улучшили подсветку ошибок, например {{ variable %} будет подсвечено как ошибка
django: работа с несколькими версиями
В связи с появлением в trunk-ветке django такой прикольной библиотеки, как newforms, пришлось на нескольких проектах переползать на trunk. При этом все остальные должны стандартно работать на версии 0.95
В системе стоит как раз 0.95 (в site-packages). Проекты работают все на связке mod_python + apache. При настройке mod_python для django-проекта используется директива PythonPath. С её помощью к путям поиска python-модулей добавляется директория с проектом. Поэтому достаточно положить дистрибутив django в ту же директорию где лежит проект.
А вот для отладки приложения приходится немного пошаманить. Я так и не разобрался в чем причина, но когда запускаешь python shell (python manage.py shell) в любом случае в списке директорий с модулями site-packages оказываются первее чем то, что добавляешь в PythonPath переменную окружения. В итоге получается что используется версия django, котрая стоит в site-packages (т.е. 0.95).
Решается всё довольно просто, но дошел я до этого не сразу, т.к. боролся чтоб всё было кошерно :-) (через python manage.py shell). Сначала грешил на ipython, но без него была та же петрушка. Наковырявшись вдоволь я сделал потом всё по быстрому и просто.
Надо установить две системные переменные в shell-окружении:- PYTHONPATH=’path_to_Django_project‘
- DJANGO_SETTINGS_MODULE=my_project.settings
После этого в любой директории набераете python или ipython и делаете импорты из моделей и работаете с ними.
Мультисайтовость в django trunk
Наконец-то появиалсь функциональность мультисайтинга в Django Framework. Напомню что раньше надо было для каждого сайта держать отдельную instance фреймвока (в смысле или отдельный fastcgi процесс или отдельно сконфигурированный виртуальный хост с mod_python).
В конфигурации проекта (settings.py) надо указывать SITE_ID, который в базе соответствует какому-то домену. И для каждого домена нужно было держать отдельный settings.py с соответствующим SITE_ID из базы.
Теперь в транк попал патч и новый middleware, который позволит в рамках одного проекта обслуживать несколько доменов. Домены будут определяться ”на лету”.
Теперь можно писать вот такие конструкции:
HOST_MIDDLEWARE_URLCONF_MAP = {
"company.com": "mydjango.app.company_urls",
"blog.example.com": "mydjango.app.blog_urls",
}
Подробнее на сайте автора и тикет.
Просмотр картинок в админке django
Пример как можно просматривать thumbnail-ы в админке django.
Достаточно в модели добавить метод image_preview который бы возвращал html-тег . Только нужно включить для метода опцию allow_tags. И добавить этот метод в свойство list_display класса конфигурации админки Admin.
См. пример кода.
def image_preview(self):
return "<img src='%s' alt=''/>" % (self.get_image_url())
image_preview.allow_tags = True
class Admin:
list_display = ('image', 'image_preview',)
FileField в Django, проблемка с удалением
Есть проблема в Django с удалением файла в FileField и ImageField из админки. Проблема давняя, а до сих пор не решенная, недавно вернулись к её обсуждению. Вот патч лежит уже три месяца как. Вчера вроде по нему появилась активность. Посмотрим…
Вот старый тикет #22 (его закрыли) и новый #2534 с более “умным” патчем.
А от себя скажу, что в модели файл получается удобнее хранить в отдельной таблице, в большинстве случаев. Т.к. при удалении ссылающегося на него объекта, сам файл можно оставить и потом использовать опять (если файл большой, то каждый раз его заливать неудобно при удалении/добавлении зависящего объекта); да плюс обычно хранится не тупо неизвестный binary файл, а что-то более интересное, нуждаещееся в описании и какой-то мета-информации, следовательно удобно было бы потом делать расширенное описание файла добавлением новых полей в таблицу по мере необходимости.
И если брать частный случай с Django, то тогда файл можно легко удалить как отдельный эелемент модели.
Обзор софта, написанного с помощью Django (Python framework) часть первая
Давно хотел сделать подобный обзор, но не было времени нормально покапаться. Главное начать, вот и делаю первый выпуск. По мере нахождения новых интересных проектов буду писать еще.
- mnemosyne – свежее, недавно нашел. На сайте написано что это персональная Wiki с версией beta, но я её хочу попробовать для одного проекта документации. Отдельно поделюсь впечатлением.
- Diamanda Wiki and Forum – интегрированный форум и Wiki. Живой сайт, работающий на этом софте есть у самого автора Riklaunim’s TechBlog. Страница на SF.
- Feedjack – агрегатор новостей (feed) в формате atom или rss. Подобный своему брату Planet. Из преимуществ перед Planet стоит выделить умение работать с категориями и тегами, а также хранить полную историю ленты (feed).
Думаю для начала вполне хватит, уже есть еще один проект на следующий обзор, но о нем позже. По мере нахождения проектов буду стараться писать более детальный обзор.






