Изменить имя загружаемого файла django
После сохранения моей модели «Продукты» я бы хотел, чтобы загруженное изображение называлось так же, как pk, например, 22.jpg или 34.jpg, если я не хочу менять формат изображения только имя. Как это может быть сделано? пример моей модели пока ниже.
Вы можете передать функцию в upload_to поле:
Мои предложения заключались бы в том, чтобы вернуть случайное имя файла вместо . . В качестве бонуса это будет более безопасно.
Что происходит, так это то, что Django вызывает эту функцию, чтобы определить, куда следует загрузить файл. Это означает, что ваша функция отвечает за возврат полного пути к файлу, включая имя файла. Ниже приведена модифицированная функция, в которой вы можете указать, куда загружать и как ее использовать:
нет, нет, не извиняйся. Я не опубликовал функцию, и это то, что нужно OP. Ваш ответ был лучше и опубликован быстрее, чем мой. +1 от меня в любом случае.
вы передаете вызываемую функцию. вместо этого вы должны передать саму функцию - upload_to=path_and_rename, .
Django 1.7 и новее не будут выполнять миграцию с такой функцией. Основываясь на ответе @miki725 и этом билете, вам нужно сделать свою функцию такой:
Нет необходимости в MEDIA_ROOT в UploadToPathAndRename(os.path.join(MEDIA_ROOT. FileField добавляет это позже.
Вы можете заменить строку, которой вы назначаете, на upload_to вызываемый объект, как описано в документации . Однако я подозреваю, что первичный ключ может быть недоступен в момент использования upload_to параметра.
По умолчанию Django сохраняет исходное имя загруженного файла, но, скорее всего, вы захотите переименовать его во что-то другое (например, идентификатор объекта). К счастью, с формами ImageField или FileField в Django вы можете назначить вызываемую функцию параметру upload_to для переименования. Например:
и в поле моделей:
В этом примере каждое загруженное изображение будет переименовано в первичный ключ объекта CardInfo, который имеет значение id_number.
Итак, мы обрабатываем это следующим образом:
Makesure the module time has been imported.
У меня есть более настраиваемая реализация решения Эйдана Юэна.
Возможно, я забыл привести еще несколько примеров, но вы можете понять это из приведенного ниже кода:
ПРЕДУПРЕЖДЕНИЕ. Каждое основанное на методе решение этой проблемы upload_to создает проблемы для предварительно сформированных файлов миграции, если вы отказываетесь от использования этих решений. Если вы используете эти решения какое-то время, а затем удалите их, старые миграции не удастся выполнить из-за отсутствия этих методов. (конечно, вы можете решить эту проблему, изменив старые файлы миграции)
Upon saving me model 'Products' I would like the uploaded image to be named the same as the pk for example 22.jpg or 34.jpg I don't want to change the format of the image just the name. How can this be done? example of my model so far below.
7 Answers 7
You can pass a function into upload_to field:
My suggestions would be to return a random filename instead of . . As a bonus, it will be more secure.
What happens is that Django will call this function to determine where the file should be uploaded to. That means that your function is responsible for returning the whole path of the file including the filename. Below is modified function where you can specify where to upload to and how to use it:
no, no don't apologise. I hadn't posted the function, and that's what OP needed. Your answer was better and posted quicker than mine. +1 from me anyway.
you are passing the called function. instead you should pass the function itself - upload_to=path_and_rename, .
The solution is working but when I am making migrations I am getting a value error saying 'Could not find wrapper'
I'm getting Could not find function wrapper when implimenting that new function. What am I doing wrong?
Django 1.7 and newer won't make migration with function like this. Based on answer by @miki725 and this ticket, you need to make your function like this:
How is instance and filename passed to the __call__ method? Wouldn't it be necessary to write upload_to=UploadToPathAndRename(. )(obj_instance, 'some_file_name') ? Plz help me to understand this python magic haha
You can replace the string your assigning to upload_to with a callable as described in the docs. However, I suspect the primary key may not be available at the point the upload_to parameter is used.
By default Django keeps the original name of the uploaded file but more than likely you will want to rename it to something else (like the object's id). Luckily, with ImageField or FileField of Django forms, you can assign a callable function to the upload_to parameter to do the renaming. For example:
and in models field:
In this example, every image that is uploaded will be rename to the CardInfo object's primary key which is id_number.
could you help understand how instance and filename values are passed with this assignment upload_to=path_and_rename ? I didn't catch this python magic. Thanks.
so, we handle it with this:
Makesure the module time has been imported.
I do have a more customizable implementation of Aidan Ewen's solution.
- You can send the fields you want to use in the filenames as a list (as pre-ordered)
- ^ one of them must be unique
- ^ else, this list must include (at least one of) the tuple of unique together fields
- ^ else, fields you sent are will be ignored and will use the uuid4 as filename
I may be forgot to give some more examples but you can understand from the code below:
WARNING: Every method-based solution to this upload_to problem is problematic for preformed migration files when you abandon using these solutions. If you use these solutions for a while and then delete them, the old migrations will fail because of the unexistence of these methods. (of course, you can fix this problem by modifying the old migration files)
Большое спасибо. Но если несложно как сохранить вместе с расширением файла и сохранением возможности установки upload_to у FileField.
Сергей Горностаев, на самом деле не нужно определять свой сторадж. Параметр upload_to может принимать функцию в качестве аргумента. В ней делаете имя какое нужно.
Пример из документации
Совет по поводу этой строки:
_, ext = path.splitext(name)
Underscore в Django традиционно используется для gettext или gettext_lazy, поэтому для ненужных аргументов лучше использовать что-нибудь другое, например, двойное подчёркивание (__).
А в данном случае проще написать так:
ext = os.path.splitext(filename)[1].lower()
neatsoft, обращение по индексу может привести к исключению, если у загружаемого файла не будет расширения.
Сергей Горностаев, проверил, всё должно быть ок:
Это с обычным split может быть такая проблема:
Для именования файлов лучше использовать хэш, а не uuid. Это гарантирует уникальность имён, и обеспечивает дедупликацию данных: сколько бы раз пользователи не заливали файл с одинаковым содержимым, он будет храниться в единственном экземпляре (исключение - файлы с одинаковым содержимым и разными расширениями, но это разумный компромисс - работать с файлами без расширений менее удобно на многих этапах).
Можно реализовать соответствующую функциональность самостоятельно:
app_name/models.py:
Но гораздо разумнее воспользоваться готовой библиотекой:
Установить hashedfilenamestorage:
pip install django-hashedfilenamestorage
и добавить следующую строку в settings.py:
Посмотрел как storage реализован в hashedfilenamestorage. В собственной реализации лучше не get_available_name переопределять, а save, и если файл существует, то просто скипать стадию сохранения.
Если не заменять стандартный storage, то при повторной записи файла с идентичным содержимым джанга добавит к имени файла последовательность случайных символов.
Каков наилучший способ переименовать фотографии с уникальным именем файла на сервере по мере их загрузки, используя django? Я хочу убедиться, что каждое имя используется только один раз. Существуют ли приложения Pinax, которые могут сделать это, возможно, с GUID?
Используйте uuid. Чтобы связать это с вашей моделью, см. Django. Документация для FileField upload_to.
Например, в вашем models.py определите следующую функцию:
Затем при определении вашего FileField / ImageField укажите get_file_path в качестве значения upload_to .
В качестве альтернативы вы можете повторно использовать аккуратный небольшой фрагмент, который создает уникальные имена файлов, а затем использует полный путь к этому файлу в качестве входных данных для вашего хэш-вызова. Это дает вам уникальные строки постоянной длины, которые вы можете сопоставить с вашими файлами.
До Django 1.6.6, 1.5.9 и 1.4.14, get_avaialable_name автоматически присвоит файлам уникальное имя, добавив символ подчеркивания. Так, например, если вы сохраните один файл «test.jpg», а затем другой файл «test.jpg» на своем сервере, первый будет называться test.jpg, а второй будет называться test_1.jpg.
Увы, это оказывается вектором DDOS для машины, посылая ей тысячи файлов нулевого байта для хранения, каждый проверяя тысячи предыдущих файлов, чтобы увидеть, каково его имя.
Как вы увидите см. в документах новая система добавляет семь случайных цифр после подчеркивания, чтобы решить эту проблему.
Django автоматически применяет уникальное имя файла. если файл уже существует, к имени файла добавляются семь уникальных символов
Протестировано на Django 2.2
Лучшим способом может быть использование общего класса в вашем helpers.py. Таким образом, вы можете использовать генератор случайных файлов в своих приложениях.
В вашем helpers.py:
А затем в вашей модели просто импортируйте вспомогательный класс:
А потом используйте это:
На момент написания этого ответа кажется, что вам больше не нужно делать ничего особенного, чтобы это произошло. Если вы настроите FileField со статическим свойством upload_to, система хранения Django будет автоматически управлять именами, так что если загружается дублирующее имя файла, Django случайным образом генерирует новое уникальное имя файла для дубликата.
Проблема такая - клиенты грузят файлы в свой профиль, но названия файлов часто могут быть кирилицей. FreeBSD, на которой крутится сервер, названия файлов кирилицей не воспринимает. Соответственно надо как-то их переименовывать при записи. Как это сделать? И, если можно, как сделать так чтобы название было уникальным для каждого файла, скажем по времени загрузки или еще как-то.
savao:названия файлов кирилицей не воспринимает
Что-то сомневаюсь. Это у тех, кто пользуется FreeBSD, ни оного русского названия файлов? Django самостоятельно подправляет название файла, что бы оно было допустимым. То есть если сохраняет с кириллицей - значит все норм. Погуглите, проблема наверное в настройках системы и локалей.
savao: И, если можно, как сделать так чтобы название было уникальным для каждого файла, скажем по времени загрузки или еще как-то.
Django самостоятельно добавляет "_" к названию, что бы оно было уникально. Еще посмотрите в документации описание атрибута upload_to у FieldFile. Там как раз про дату и др.
В доках я смотрел, но там немного не то. Там предлагают файлы распихивать по папочкам вида /filefolder/%Y/%m/%d А само название неизменное остается. Или я что-то не так ччитал. А про файлы, может на самом деле проблемы с настройками фри, но я не специалист по этим вопросам. Но знаю что при попытке скопирывать на сервер файл с кирилическим названием получается файл с названием ввиде кучи знаков вопроса, а при попытке загрузить подобный файл через джангу, получается куча ругани о кодировках. Попробую поговорить со спецами по фре, может чего подскажут. Но я где-то в блогах читал что джанга и сама с кирилицей не очень дружит и если грузит файлы с кириличесикими названиями, то заменяет все буквы на знаки "_" Может это уже устаревшая инфа. Я же тока недавно начал с ней работать, так что многого еще не успел освоить.
savao:Но я где-то в блогах читал что джанга и сама с кирилицей не очень дружит
Это бред. Не была бы Django так популярен, если бы криво работал с кириллицей. Главное что бы все хранилось или преобразовывалось в utf8. "_" добавляется к названию файла для уникальности.
Читайте также: