Как удалить старое изображение при обновлении ImageField? - PullRequest
30 голосов
/ 21 мая 2010

Я использую Django для создания сайта для стандартных фотографий, в моей модели есть ImageField, проблема в том, что когда пользователь обновляет поле изображения, исходный файл изображения не удаляется с жесткого диска.

Как удалить старые изображения после обновления?

Ответы [ 8 ]

24 голосов
/ 21 августа 2012

Использование django-cleanup

pip install django-cleanup

settings.py

INSTALLED_APPS = (
    ...
    'django_cleanup', # should go after your apps

)
14 голосов
/ 21 мая 2010

Вам придется удалить старое изображение вручную.

Абсолютный путь к изображению сохраняется в your_image_field.name. Так что вы бы сделали что-то вроде:

os.remove(your_image_field.name)

Но для удобства вы можете использовать связанный объект FieldFile, который предоставляет легкий доступ к базовому файлу, а также предоставляет несколько удобных методов. Смотри http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield-and-fieldfile

13 голосов
/ 11 июня 2010

Используйте этот метод сохранения в вашей модели:

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)

У меня работает на моем сайте. Эта проблема беспокоила меня также, и я не хотел делать сценарий очистки вместо хорошей бухгалтерии во-первых. Дайте мне знать, если с этим возникнут проблемы.

12 голосов
/ 26 мая 2013

Перед обновлением экземпляра модели вы можете использовать метод удаления объекта 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

3 голосов
/ 29 октября 2018

Вы можете определить pre_save приемник в моделях:

@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.

3 голосов
/ 24 декабря 2014

Вот приложение, которое по умолчанию удаляет потерянные файлы: 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()
1 голос
/ 07 июля 2019

попробуйте, это будет работать, даже если старый файл удален

def logo_file(instance, filename):
this = business.objects.get(id=instance.id)
try:
    if this.logo is not None:
        path = "%s" % (this.logo)
        os.remove(path)
finally:
    pass..

код будет работать даже без "try ... finally", но это создаст проблему, если файл был случайно удален.Дайте мне знать, если возникнут проблемы.

0 голосов
/ 15 июня 2019

Завершение ответа Криса Лоулора, попробовал это и работает.

from YOURAPP.settings import BASE_DIR

try:
    os.remove(BASE_DIR + user.userprofile.avatarURL)
except Exception as e:
    pass 

URL имеет шаблон /media/mypicture.jpg

...