Страницы

Поиск по вопросам

четверг, 13 февраля 2020 г.

Динамический путь для upload_to в модели django (models.FileField)

#python #fileupload #django


Здравствуйте, 
В django до версии 1.4 была возможность в модели для models.FileField указать "динамически"
создаваемый путь хранения файлов в переменную upload_to
models.py
#...
attach        = models.FileField(verbose_name=u'Приложение', blank=True, upload_to=lambda
instance, filename: 'attach/%s/%s' % (instance.id,filename))

D django версии 1.4 похоже id присваивается позже и поэтому instance.id = None и
так же instance.pk = None. Подскажите как можно указать в путь именно id модели.    


Ответы

Ответ 1



Ваш вопрос немного ставит в тупик, потому как лично у меня в версии до 1.4 также id не был доступен в upload_to. Вообще вопрос хранения путей файлов достаточно избит. По мне, так самый нормальный вариант с построением хеша от timestamp + имя файла и создание директорий по первым 4м символам хеша upload_to = 'upload_path/%s/%s/%s.jpg' % (hash[:1], hash[2:3], hash) UPDATE Касательно именно id в имени файла. Вам надо после сохранения файла, т.е. после присвоения id в базе генерировать новый путь и соответственно перемещать файл по новому пути. На мое субъективное мнение уж слишком затратная операция получается. UPDATE2 import uuid def get_file_path(instance, filename): ext = filename.split('.')[-1] filename = "%s.%s" % (uuid.uuid4(), ext) return 'uploads/%s/%s/%s.jpg' % (filename[:1], filename[2:3], filename) и в модели file = models.FileField(upload_to=get_file_path, null=True, blank=True, verbose_name=_(u'Contact list'))

Ответ 2



Согласно документации для версий до 1.4 включительно: In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field Соответсвенно, такое поведение было и раньше, возможно вы ошиблись. Да, можно сделать грязный хак для решения этой проблемы с отлавливанием сигнала сохранения модели и перемещения файла по новому пути... надо ли оно вам - это должны решить сами. Либо, раз уж в документации говорится именно об AutoField, попробуйте заменить поле id у модели на что-то свое (хэш от файла? UUID? Сами решайте). Возможно, этот трюк сработает.

Ответ 3



ID будет только после вставки ряда, а ряд вставится только после записи всех полей. Поэтому нельзя знать ID пока объект не сохранен. Самое простое — в транзакции сначала сохранить с attach=None, потом обновить поле и пересохранить. Как-то в таком духе: with transaction.commit_on_success(): file = File(..., attach=None) file.save() file.attach = attachment file.save() В рамках оптимизации можно сделать предвыборку ID, но это не очень красиво и vendor-specific решение, которое сложно переносить между базами данных. Зато избавляет от пары INSERT+UPDATE, ограничиваясь одной вставкой. Для PostgreSQL, который умеет SEQUENCEs, например будет что-то в духе: from django.db import connection assert connection.vendor == "postgresql" cursor = connection.cursor() cursor.execute("SELECT nextval('seq_files_id')") new_id, = cursor.fetchone() file = File(id=new_id, ...) file.save()

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

Отправить комментарий