Pau*_*jan 273 django caching image django-models
在我的模型中,我有:
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
Run Code Online (Sandbox Code Playgroud)
这首次remote_image变化很有效.
当有人修改remote_image了别名时,如何获取新图像?其次,是否有更好的方法来缓存远程图像?
Jos*_*osh 405
虽然现在有点晚了,但是让我为其他人发布这个解决方案.实质上,您希望覆盖__init__方法,models.Model以便保留原始值的副本.这使得您无需进行其他数据库查找(这总是一件好事).
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, *args, **kwargs):
if self.name != self.__original_name:
# name changed - do something here
super(Person, self).save(force_insert, force_update, *args, **kwargs)
self.__original_name = self.name
Run Code Online (Sandbox Code Playgroud)
ipe*_*kiy 188
我使用以下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])
Run Code Online (Sandbox Code Playgroud)
用法:
>>> 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)
>>>
Run Code Online (Sandbox Code Playgroud)
请注意,此解决方案仅适用于当前请求的上下文.因此它主要适用于简单的情况.在并发环境中,多个请求可以同时操作同一个模型实例,您肯定需要一种不同的方法.
Chr*_*att 142
最好的方法是使用pre_save信号.在问及回答这个问题时,09年可能不是一个选项,但是今天看到这个问题的任何人都应该这样做:
@receiver(pre_save, sender=MyModel)
def do_something_if_changed(sender, instance, **kwargs):
try:
obj = sender.objects.get(pk=instance.pk)
except sender.DoesNotExist:
pass # Object is new, so field hasn't technically changed, but you may want to do something else here.
else:
if not obj.some_field == instance.some_field: # Field has changed
# do something
Run Code Online (Sandbox Code Playgroud)
zgo*_*oda 135
现在直接回答:检查字段值是否已更改的一种方法是在保存实例之前从数据库中获取原始数据.考虑这个例子:
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)
Run Code Online (Sandbox Code Playgroud)
使用表单时同样适用.您可以在ModelForm的clean或save方法中检测它:
class MyModelForm(forms.ModelForm):
def clean(self):
cleaned_data = super(ProjectForm, self).clean()
#if self.has_changed(): # new instance or existing updated (form has data to save)
if self.instance.pk is not None: # new instance only
if self.instance.f1 != cleaned_data['f1']:
print 'f1 changed'
return cleaned_data
class Meta:
model = MyModel
exclude = []
Run Code Online (Sandbox Code Playgroud)
Ser*_*rge 54
自从Django 1.8发布以来,您可以使用from_db classmethod来缓存remote_image的旧值.然后在save方法中,您可以比较字段的旧值和新值以检查值是否已更改.
@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!
Run Code Online (Sandbox Code Playgroud)
Lee*_*nde 18
请注意,字段更改跟踪在django-model-utils中可用.
https://django-model-utils.readthedocs.org/en/latest/index.html
laf*_*ste 15
如果您使用的是表单,则可以使用Form的changed_data(docs):
class AliasForm(ModelForm):
def save(self, commit=True):
if 'remote_image' in self.changed_data:
# do things
remote_image = self.cleaned_data['remote_image']
do_things(remote_image)
super(AliasForm, self).save(commit)
class Meta:
model = Alias
Run Code Online (Sandbox Code Playgroud)
小智 9
游戏已经很晚了,但这是克里斯普拉特答案transaction的一个版本,通过使用块和牺牲性能来防止竞争条件select_for_update()
@receiver(pre_save, sender=MyModel)
@transaction.atomic
def do_something_if_changed(sender, instance, **kwargs):
try:
obj = sender.objects.select_for_update().get(pk=instance.pk)
except sender.DoesNotExist:
pass # Object is new, so field hasn't technically changed, but you may want to do something else here.
else:
if not obj.some_field == instance.some_field: # Field has changed
# do something
Run Code Online (Sandbox Code Playgroud)
另一个迟到的答案,但如果您只是想查看新文件是否已上传到文件字段,请尝试以下操作:(改编自 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
Run Code Online (Sandbox Code Playgroud)
从Django 1.8开始from_db,就像Serge提到的那样.事实上,Django文档将此特定用例作为示例:
https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
下面是一个示例,说明如何记录从数据库加载的字段的初始值
这在 Django 1.8 中对我有用
def clean(self):
if self.cleaned_data['name'] != self.initial['name']:
# Do something
Run Code Online (Sandbox Code Playgroud)
有一个属性 __dict__ 将所有字段作为键,将值作为字段值。所以我们可以只比较其中两个
只需将模型的保存功能更改为下面的功能
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if self.pk is not None:
initial = A.objects.get(pk=self.pk)
initial_json, final_json = initial.__dict__.copy(), self.__dict__.copy()
initial_json.pop('_state'), final_json.pop('_state')
only_changed_fields = {k: {'final_value': final_json[k], 'initial_value': initial_json[k]} for k in initial_json if final_json[k] != initial_json[k]}
print(only_changed_fields)
super(A, self).save(force_insert=False, force_update=False, using=None, update_fields=None)
Run Code Online (Sandbox Code Playgroud)
class A(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
senior = models.CharField(choices=choices, max_length=3)
timestamp = models.DateTimeField(null=True, blank=True)
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if self.pk is not None:
initial = A.objects.get(pk=self.pk)
initial_json, final_json = initial.__dict__.copy(), self.__dict__.copy()
initial_json.pop('_state'), final_json.pop('_state')
only_changed_fields = {k: {'final_value': final_json[k], 'initial_value': initial_json[k]} for k in initial_json if final_json[k] != initial_json[k]}
print(only_changed_fields)
super(A, self).save(force_insert=False, force_update=False, using=None, update_fields=None)
Run Code Online (Sandbox Code Playgroud)
仅生成那些已更改字段的输出
{'name': {'initial_value': '1234515', 'final_value': 'nim'}, 'senior': {'initial_value': 'no', 'final_value': 'yes'}}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
140875 次 |
| 最近记录: |