Загрузка файлов в Django. FileField & upload_to.

02 Jan 2009


На момент выхода версии 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.