views:

785

answers:

5

In my model I have :

class Alias(MyBaseModel):
    remote_image = models.URLField(max_length=500, null=True, help_text="A URL that is downloaded and cached for the image. Only
 used when the alias is made")
    image = models.ImageField(upload_to='alias', default='alias-default.png', help_text="An image representing the alias")


    def save(self, *args, **kw):
        if (not self.image or self.image.name == 'alias-default.png') and self.remote_image :
            try :
                data = utils.fetch(self.remote_image)
                image = StringIO.StringIO(data)
                image = Image.open(image)
                buf = StringIO.StringIO()
                image.save(buf, format='PNG')
                self.image.save(hashlib.md5(self.string_id).hexdigest() + ".png", ContentFile(buf.getvalue()))
            except IOError :
                pass

Which works great for the first time the remote_image changes.

How can I fetch a new image when someone has modified the remote_image on the alias? And secondly, is there a better way to cache a remote image?

+1  A: 

While this doesn't actually answer your question, I'd go about this in a different way.

Simply clear the remote_image field after successfully saving the local copy. Then in your save method you can always update the image whenever remote_image isn't empty.

If you'd like to keep a reference to the url, you could use an non-editable boolean field to handle the caching flag rather than remote_image field itself.

SmileyChris
A: 

as an extension of SmileyChris' answer, you can add a datetime field to the model for last_updated, and set some sort of limit for the max age you'll let it get to before checking for a change

Jiaaro
+4  A: 

And now for direct answer: the only way to check if the value for the field has changed is to fetch original data from database before saving instance. Consider this example:

class MyModel(models.Model):
    f1 = models.CharField(max_length=1)

    def save(self, *args, **kw):
        if self.pk is not None:
            orig = MyModel.objects.get(pk=self.pk)
            if orig.f1 != self.f1:
                print 'f1 changed'
        super(MyModel, self).save(*args, **kw)
zgoda
If you decide to go with this type of solution over Josh's (which I really like), here's a snippit I use sometimes to generalize this type of thing: http://zmsmith.com/2010/05/django-check-if-a-field-has-changed/
Zach
+5  A: 

Though it's a bit late, let me throw out this solution for others that come across this post. Essentially, you want to override the init method of models.Model so that you keep a copy of the original value. This makes it so that you don't have to do another DB lookup (which is always a good thing).

class Person(models.Model):
  name = models.CharField()

  __original_name = None

  def __init__(self, *args, **kwargs):
    super(Person, self).__init__(*args, **kwargs)
    self.__original_name = self.name

  def save(self, force_insert=False, force_update=False):
    if self.name != self.__original_name:
      # name changed - do something

    super(Person, self).save(force_insert, force_update)
Josh
instead of overwriting init, I'd use the post_init-signal http://docs.djangoproject.com/en/dev/ref/signals/#post-init
vikingosegundo
Overriding methods is recommended by the Django documentation: http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods
Colonel Sponsz
+1  A: 

Josh, Thanks, your answer is spot on. You're missing 'self' in the init command though.

Harel
Thanks, added. (Didn't see this until today after reviewing a recent comment)
Josh