Как удалить старое изображение при обновлении ImageField?
Я использую Django для создания сайта с фотографиями, в моей модели есть ImageField, проблема в том, что когда пользователь обновляет поле изображения, исходный файл изображения не удаляется с жесткого диска.
Как я могу удалить старые изображения после обновления?
Ответы
Ответ 1
Вам придется удалить старое изображение вручную.
Абсолютный путь к изображению хранится в your_image_field.name
. Так что вы бы сделали что-то вроде:
os.remove(your_image_field.name)
Но для удобства вы можете использовать связанный объект FieldFile, который обеспечивает легкий доступ к базовому файлу, а также предоставляет несколько удобных методов. См. Http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield-and-fieldfile.
Ответ 2
Используйте django-cleanup
pip install django-cleanup
settings.py
INSTALLED_APPS = (
...
'django_cleanup', # should go after your apps
)
Ответ 3
Используйте этот настраиваемый метод сохранения в вашей модели:
def save(self, *args, **kwargs):
try:
this = MyModelName.objects.get(id=self.id)
if this.MyImageFieldName != self.MyImageFieldName:
this.MyImageFieldName.delete()
except: pass
super(MyModelName, self).save(*args, **kwargs)
Он работает для меня на моем сайте. Эта проблема тоже беспокоила меня, и я не хотел делать очистку script вместо хорошей бухгалтерии в первую очередь. Сообщите мне, есть ли с ним проблемы.
Ответ 4
Перед обновлением экземпляра модели вы можете использовать метод FileField
объекта FileField
. Например, если FileField
или ImageField
назван как photo
а экземпляр вашей модели - profile
, то следующий файл удалит файл с диска.
profile.photo.delete(False)
Для получения дополнительной информации, вот документ Django
https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.fields.files.FieldFile.delete
Ответ 5
Вы можете определить pre_save
reciever в моделях:
@receiver(models.signals.pre_save, sender=UserAccount)
def delete_file_on_change_extension(sender, instance, **kwargs):
if instance.pk:
try:
old_avatar = UserAccount.objects.get(pk=instance.pk).avatar
except UserAccount.DoesNotExist:
return
else:
new_avatar = instance.avatar
if old_avatar and old_avatar.url != new_avatar.url:
old_avatar.delete(save=False)
Мои аватры имеют уникальный URL для каждого человека, например, "avatars/ceb47779-8833-4719-8711-6f4e5cabb2b2.png". Если пользователь загружает новое изображение с другим расширением, например jpg, приемник delete_file_on_change_extension удаляет старое изображение, а затем сохраняет новое с помощью URL-адреса "avatars/ceb47779-8833-4719-8711-6f4e5cabb2b2.jpg" (в данном случае). Если пользователь загружает новое изображение с тем же расширением, django перезаписывает старое изображение в хранилище (на диске), поскольку пути к изображениям совпадают. Это прекрасно работает с AWS S3 django-storage.
Ответ 6
Вот приложение, которое по умолчанию удаляет файлы-сироты: django-smartfields.
Он будет удалять файлы всякий раз, когда:
-
Значение поля
- было заменено новым (загружено или установлено вручную)
Поле
- очищается через форму (в случае, если это поле не требуется, конечно)
- удаляется экземпляр модели, содержащий поле.
Можно отключить эту функцию очистки с помощью аргумента: ImageField(keep_orphans=True)
для каждого поля или глобально в настройках SMARTFIELDS_KEEP_ORPHANS = True
.
from django.db import models
from smartfields import fields
class MyModel(models.Model):
image = fields.ImageField()
document = fields.FileField()
Ответ 7
Попробуйте, это будет работать, даже если старый файл будет удален
def logo_file(instance, filename):
try:
this = business.objects.get(id=instance.id)
if this.logo is not None:
path = "%s" % (this.logo)
os.remove(path)
finally:
pass..
Код будет работать даже без "try.. finally", но он будет создавать проблему, если файл был случайно удален.
изменено: перемещение соответствия модели внутри "try", чтобы оно не выдавало ошибку при регистрации пользователя
Дайте мне знать, если есть какие-либо проблемы.
Ответ 8
Завершая ответ Криса Лоулора, попробовал это и работает.
from YOURAPP.settings import BASE_DIR
try:
os.remove(BASE_DIR + user.userprofile.avatarURL)
except Exception as e:
pass
URL имеет шаблон /media/mypicture.jpg