在我的模型中我有:
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 1.8发布以来,你可以使用from_db类方法来缓存remote_image的旧值。然后在保存方法中,您可以比较字段的旧值和新值,以检查该值是否已更改。
@classmethod
def from_db(cls, db, field_names, values):
new = super(Alias, cls).from_db(db, field_names, values)
# cache value went from the base
new._loaded_remote_image = values[field_names.index('remote_image')]
return new
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if (self._state.adding and self.remote_image) or \
(not self._state.adding and self._loaded_remote_image != self.remote_image):
# If it is first save and there is no cached remote_image but there is new one,
# or the value of remote_image has changed - do your stuff!
我使用以下mixin:
from django.forms.models import model_to_dict
class ModelDiffMixin(object):
"""
A model mixin that tracks model fields' values and provide some useful api
to know what fields have been changed.
"""
def __init__(self, *args, **kwargs):
super(ModelDiffMixin, self).__init__(*args, **kwargs)
self.__initial = self._dict
@property
def diff(self):
d1 = self.__initial
d2 = self._dict
diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
return dict(diffs)
@property
def has_changed(self):
return bool(self.diff)
@property
def changed_fields(self):
return self.diff.keys()
def get_field_diff(self, field_name):
"""
Returns a diff for field if it's changed and None otherwise.
"""
return self.diff.get(field_name, None)
def save(self, *args, **kwargs):
"""
Saves model and set initial state.
"""
super(ModelDiffMixin, self).save(*args, **kwargs)
self.__initial = self._dict
@property
def _dict(self):
return model_to_dict(self, fields=[field.name for field in
self._meta.fields])
用法:
>>> p = Place()
>>> p.has_changed
False
>>> p.changed_fields
[]
>>> p.rank = 42
>>> p.has_changed
True
>>> p.changed_fields
['rank']
>>> p.diff
{'rank': (0, 42)}
>>> p.categories = [1, 3, 5]
>>> p.diff
{'categories': (None, [1, 3, 5]), 'rank': (0, 42)}
>>> p.get_field_diff('categories')
(None, [1, 3, 5])
>>> p.get_field_diff('rank')
(0, 42)
>>>
Note
请注意,此解决方案仅在当前请求的上下文中工作良好。因此,它主要适用于简单的情况。在并发环境中,多个请求可以同时操作同一个模型实例,您肯定需要一种不同的方法。
这是另一种方法。
class Parameter(models.Model):
def __init__(self, *args, **kwargs):
super(Parameter, self).__init__(*args, **kwargs)
self.__original_value = self.value
def clean(self,*args,**kwargs):
if self.__original_value == self.value:
print("igual")
else:
print("distinto")
def save(self,*args,**kwargs):
self.full_clean()
return super(Parameter, self).save(*args, **kwargs)
self.__original_value = self.value
key = models.CharField(max_length=24, db_index=True, unique=True)
value = models.CharField(max_length=128)
根据文档:验证对象
full_clean()执行的第二步是调用Model.clean()。应该重写此方法,以便在模型上执行自定义验证。
此方法应用于提供自定义模型验证,并根据需要修改模型上的属性。例如,你可以使用它来自动为一个字段提供一个值,或者进行验证,需要访问多个字段:
本质上,你想要重写模型的__init__方法。模型,以便保留原始值的副本。这使得您不必再执行另一个DB查找(这总是一件好事)。
class Person(models.Model):
name = models.CharField()
__original_name = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__original_name = self.name
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.name != self.__original_name:
# name changed - do something here
super().save(force_insert, force_update, *args, **kwargs)
self.__original_name = self.name
另一个迟来的答案,但如果你只是想看看一个新文件是否已经上传到一个文件字段,试试这个:(改编自Christopher Adams对链接http://zmsmith.com/2010/05/django-check-if-a-field-has-changed/的评论在zach的评论这里)
更新链接:https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
def save(self, *args, **kw):
from django.core.files.uploadedfile import UploadedFile
if hasattr(self.image, 'file') and isinstance(self.image.file, UploadedFile) :
# Handle FileFields as special cases, because the uploaded filename could be
# the same as the filename that's already there even though there may
# be different file contents.
# if a file was just uploaded, the storage model with be UploadedFile
# Do new file stuff here
pass