ImageField не удаляет файл при использовании os.unlink()

#python #django #image #delete-file #imagefield

#python #django #изображение #удалить-файл #imagefield

Вопрос:

У меня есть эта модель:

 class UserProfile(models.Model):
    """(UserProfile description)"""
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=upload_to)

    def save(self):
        os.unlink(self.image.path)
        super(UserProfile, self).save()
  

Скрипт завершает работу с unlink() методом с ошибкой и сообщает, что файл не может быть найден. Есть идеи?

Ошибка гласит

(2, ‘Такого файла или каталога нет’)

Ответ №1:

Вам нужна более конкретная отладка. Кроме того, способ, которым вы написали код, вероятно, гарантирует возникновение ошибок. Я не совсем уверен, но я не удивлюсь, если значение для UserProfile.image не задано до создания записи UserProfile.

Поэтому я бы переписал ваш код таким образом:

 class UserProfile(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=upload_to)

    def save(self):
        if self.image.path:
            try:
                os.unlink(self.image.path)
            except Exception, inst:
                raise Exception("Unable to delete %s. Error: %s" % (self.image.path, inst))
        super(UserProfile, self).save()
  

Обновить

Теперь, когда я думаю об этом, имеет смысл, что как только вы вызываете save, новая информация уже находится в self.image. Если ваша цель — удалить старые изображения при сохранении нового, вам нужно будет использовать сигнал pre_save в Django для извлечения старой записи (и, следовательно, старого пути к изображению) перед сохранением изображения. Теоретически, вы могли бы поместить это в save метод UserProfile модели, но поскольку это предназначено как побочное действие, которое напрямую не влияет на текущую запись, я бы сохранил его отдельно.

Вот пример реализации:

 from django.db.models import signals
def delete_old_image(sender, instance, using=None):
    try:
        old_record = sender.objects.get(pk=instance.pk)
        os.unlink(old_record.image.path)
    except sender.DoesNotExist:
        pass
signals.pre_save.connect(delete_old_image, sender=UserProfile)
  

Вы бы поместили это в свой models.py файл.

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

1. Хорошо, я к чему-то приближаюсь. Получается self.image. путь ссылается на новое изображение, а не на то, которое уже существует. Есть ли причина, почему это так?

2. Я бы предположил, что это связано с тем фактом, что значение для self.image устанавливается перед сохранением. save функция не принимает набор значений и не помещает его в запись модели. Скорее, он сохраняет в базе данных значения, которые уже есть в модели. Если вы серьезно относитесь к выполнению этого удаления, вы хотите использовать pre_save сигнал, описанный здесь: docs.djangoproject.com/en/dev/ref/signals /… . Я обновлю свой ответ.