在我的模型中我有:

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

这在remote_image第一次改变的时候工作得很好。

当有人修改了别名上的remote_image时,我如何获取一个新的图像?其次,是否有更好的方法来缓存远程映像?


当前回答

我有点晚了,但我也找到了这个解决方案: Django脏域

其他回答

用David Cramer的解决方案怎么样:

http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/

我曾经这样成功地使用过:

@track_data('name')
class Mode(models.Model):
    name = models.CharField(max_length=5)
    mode = models.CharField(max_length=5)

    def save(self, *args, **kwargs):
        if self.has_changed('name'):
            print 'name changed'

    # OR #

    @classmethod
    def post_save(cls, sender, instance, created, **kwargs):
        if instance.has_changed('name'):
            print "Hooray!"

这在Django 1.8中是适用的

def clean(self):
    if self.cleaned_data['name'] != self.initial['name']:
        # Do something

我对@iperelivskiy的解决方案的看法是:在大规模的情况下,为每个__init__创建_initial字典是昂贵的,而且大多数时候是不必要的。我稍微改变了mixin,这样它只在你显式地告诉它这样做(通过调用instance.track_changes)时才记录更改:

from typing import KeysView, Optional
from django.forms import model_to_dict

class TrackChangesMixin:
    _snapshot: Optional[dict] = None

    def track_changes(self):
        self._snapshot = self.as_dict

    @property
    def diff(self) -> dict:
        if self._snapshot is None:
            raise ValueError("track_changes wasn't called, can't determine diff.")
        d1 = self._snapshot
        d2 = self.as_dict
        diffs = [(k, (v, d2[k])) for k, v in d1.items() if str(v) != str(d2[k])]
        return dict(diffs)

    @property
    def has_changed(self) -> bool:
        return bool(self.diff)

    @property
    def changed_fields(self) -> KeysView:
        return self.diff.keys()

    @property
    def as_dict(self) -> dict:
        return model_to_dict(self, fields=[field.name for field in self._meta.fields])

在我的解决方案是覆盖目标字段类的pre_save()方法之前,我有这种情况,它只在字段被更改时才会被调用 FileField有用 例子:

class PDFField(FileField):
    def pre_save(self, model_instance, add):
        # do some operations on your file 
        # if and only if you have changed the filefield

劣势: 如果你想做任何(post_save)操作,比如在某些作业中使用创建的对象(如果某些字段已更改),则无用

注意,字段更改跟踪在django-model-utils中是可用的。

https://django-model-utils.readthedocs.org/en/latest/index.html