0

I have this model:

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()

The script fails on the unlink() method, and says the file cannot be found. Any ideas?

The error says

(2, 'No such file or directory')

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
dotty
  • 40,405
  • 66
  • 150
  • 195

1 Answers1

2

You need more specific debugging. Furthermore, the way you've written the code probably ensures errors will happen. I'm not entirely sure, but I wouldn't be surprised if the value for UserProfile.image isn't set before a UserProfile record is created.

So I would rewrite your code thusly:

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()

Update

Now that I think about it, it does make sense that once you're calling save, the new information is already in self.image. If your goal is to delete the old images when saving the new, you are going to need to use the pre_save signal in Django to retrieve the old record (and thus the old image path) prior to saving the image. In theory, you could put this in the save method of the UserProfile model, but since it's intended as a side action that does not directly affect the current record, I'd keep it separate.

Here's a sample implementation:

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)

You would put this in your models.py file.

Jordan Reiter
  • 20,467
  • 11
  • 95
  • 161
  • Ok, I'm getting somewhere. Turns out self.image.path refers to the new image, not the one which already exists. Any reason why this is the case? – dotty May 01 '11 at 20:29
  • I would assume it has to do with the fact that the value for self.image is set prior to saving. the `save` function does not take a set of values and put it in the model record. Rather, it saves to the database the values that are already in the model. If you are serious about performing this deletion, you want to use the `pre_save` signal described here: http://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.pre_save. I'll update my answer. – Jordan Reiter May 02 '11 at 18:19