LINUX.ORG.RU

Хэширование загружаемых файлов

 


0

1

Хочется при загрузке файла (изображения) прохэшировать его что-бы во-первых, не допустить загрузку одинаковых файлов, а во-вторых сгенерировать человекочитаемый идетификатор файлу. Ещё хотелось использовать хэш в качестве имени файла. Вопрос, в какой момент именно нужно хэшировать?

Сначала чтобы дать файлу имя попробовал указать для ImageField модели upload_to функцию в которой и хэшировал, но она почему-то вызывается дважды (почему? я так и не нашёл ответ), притом второй раз файл читается как пустой.

Дальше попробовал переопределить метод save модели, но до вызова метода предка файл опять таки читается как пустой, т.е. сам он ещё не сохранён, а после вызова хэшировать поздно ибо хэш нужен как ключ.

Вроде можно прохэшировать в отображении (view) между form.save(commit=False) и model.save(), но это выглядит как костыль, хочется держать его чистым. Вроде можно перенести это в валидацию формы, но непонятно как читать файл оттуда и как сохранять хэш в бд.

tl;dr Не понимаю, как в рамках ORM джанги без костылей хэшировать загружаемые файлы.

★★★

Последнее исправление: Kalashnikov (всего исправлений: 1)

Ой да, была такая беда, но не помню как решил %)

Помню хотел в сырцах джанги найти место где генерится имя, и перегрузить его, но оно было в какомто огромном методе внутри цепочки if'ов. Плохо вобщем всё было.

redixin ★★★★
()
Ответ на: комментарий от Bers

Это годится для имени файла, да и для ид для юзера, но уникальность не проверить.

Kalashnikov ★★★
() автор топика

Метод clean у модели перегрузи и там проверяй, тогда и в админке будет нормально работать.

pi11 ★★★★★
()
Ответ на: комментарий от pi11

Ага, понял.

try:
	Image.objects.get(hash=hash)
except Image.DoesNotExist:
	self.instance.hash = hash
	return cleaned_data

raise forms.ValidationError("Duplicate image: " + hash)
А имя файла никак не задать, только скопировать? Хотя на это в принципе можно и забить.

Kalashnikov ★★★
() автор топика
Ответ на: комментарий от Kalashnikov

А имя файла никак не задать

А для этого наверное лучше метод save перегрузить.

pi11 ★★★★★
()

Я бы порекомендовал Вам сделать обработчик к сигналу post_save. Как-то так

from django.db.models.signals import post_save

def calc_hash_sm(sender, instance, **kwargs):
    ### Обработчик сигнала post_save для модели SampleModel

    ### Здесь считаем хэш

post_save.connect(calc_hash_sm, sender=SampleModel)
k0valenk0_igor ★★★
()
Ответ на: комментарий от pi11

Хм.. Вы правы - никак. Но ведь можно поместить обработчик сигнала pre_save, не дающий сохранять данные. А в модели в методе save отработать ситуацию по try ... except

k0valenk0_igor ★★★
()
Ответ на: комментарий от pi11

Как мне кажется, мы правы оба. Во всяком случае, работать будут оба метода, а в остальном «на вкус на цвет, - как в ухо дам так и поверишь»)))).

Но вообще-то, с учетом валидации форм, Ваше решение конкретной проблемы, наверное удобнее. Да.

k0valenk0_igor ★★★
()
Ответ на: комментарий от redixin

Чтобы в админке тоже генерировались имена файлов - то самое на мой взгляд правильно решение - это использовать аттрибут upload_to у ImageField/FileField. https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.Fil...

upload_to может быть callable.

pi11 ★★★★★
()
Ответ на: комментарий от pi11

Я в ТС писал что пробовал. Почему-то он вызывается дважды: Первый раз нормально, а второй раз instance.filefiled.read() возвращает пыстые данные, соответственно для всех файлов имя файла переопределяется как один и тот-же хэш от пустых данных.

Ну и получается что если хочется и имя файла и поле в бд, придётся хэшировать дважды или костылять?

Kalashnikov ★★★
() автор топика
Ответ на: комментарий от Kalashnikov

Почему-то он вызывается дважды

А ты в этом методе не считай hash заново а используй значение instance.hash.

pi11 ★★★★★
()
Последнее исправление: pi11 (всего исправлений: 1)

А вспомнил. Я хотел в качестве имени делать pk записи, но благополучно забил на эту идею.

redixin ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.