在Django模型(.save()
)上执行更新/创建时,我希望能够“插入”并比较一些特定的属性,以他们以前设置(如果他们以前存在的话)。Django:在更新模型之前,我想“查看”其以前的属性
我在想前保存信号,与原始模型做一个.objects.get(instance.id)
,但这感觉很浪费。另外,验证已经发生在pre_save()
?
在Django模型(.save()
)上执行更新/创建时,我希望能够“插入”并比较一些特定的属性,以他们以前设置(如果他们以前存在的话)。Django:在更新模型之前,我想“查看”其以前的属性
我在想前保存信号,与原始模型做一个.objects.get(instance.id)
,但这感觉很浪费。另外,验证已经发生在pre_save()
?
注意full_clean()不会自动当你调用模型的save()方法
然后,对pre-save signal
,请注意你的实例调用正在保存的消息作为参数发送。由于模型的前一版本只存在于数据库中,我看不出有什么地方你可以得到属性的前值...
你不告诉你为什么要做到这一点,所以很难这么说,但是其他的解决方案,我想的现在:
* defining a custom signal that is sent everytime the attributes you are interested in are modified... This signal would then send two arguments : new value, old value
* perform the check directly when setting the attributes
如果你提供更多的细节,这可能是更容易...
编辑:
这是正确的...如果你发出一个自定义'foo_has_updated',你不能确定修改是否被保存。
在这种情况下,我想你可以缓存感兴趣的变量,你在初始化实例,并捕捉后保存或预存的信号。
* With pre-save, you would be able to pre-process the data, but the saving operation might fail
* With post-save, you would be sure that the data has been saved.
缓存的变量可以做这样的:
class CachedModel(models.Model):
cached_vars = [var1, var2, varN]
def __init__(self, *args, **kwargs):
super(CachedModel, self).__init__(*args, **kwargs)
self.var_cache = {}
for var in self.cached_vars:
self.var_cache[var] = copy.copy(getattr(self, var))
或者是这样的......然后,在信号处理程序:
def post_save_handler(sender, **kwargs):
instance = kwargs["instance"]
[(instance.var_cache[var], getattr(instance, var)) for var in instance.cached_var]
#[(<initial value>, <saved value>)
和你有你需要的东西(我认为)!!!
保存前,您可以询问数据库中当前存储的值。我这样做只记录更改的值,但每次保存时都会导致另一个数据库查询。
虽然我非常赞同Sébastien Piquemal's answer我最终最终同时使用了pre_save
和post_save
信号。我不是重写__init__()
,而是在pre_save
中做了非常类似的事情,然后检查/比较post_save
中的值,并在满足某些条件时从那里发出自定义信号。
我想我仍然会接受他的答案,花在它上面的时间。我没有看到我们在做什么与众不同,除了我正在做一个信号的工作,而他正在做初始化工作。
这里是我的想法:玩弄性质。
说你有这个类:
class Foo(models.Model):
name = models.CharField()
相反,重命名你的领域(你不会需要迁移,如果它是第一次 你这样做)和:
class Foo(models.Model):
_name = models.CharField()
@property
def name(self):
return self._name
@name.setter
def name(self, new_value):
if not getattr(self, '_initial_name', False):
self._initial_name = self._name
if new_value != self._initial_name:
self._name_changed = True
else:
self._name_changed = False
self._name = new_value
我们为您的Foo实例添加了两个属性:'_initial_name'和 '_name_changed'以及一个属性'name'。这些不是模型字段,并且将不会将 保存到数据库。此外,只要'name'属性处理所有内容,您就不必再乱用'_name' 字段。
def handle_pre_save(sender, **kwargs):
foo = kwargs['instance']
if getattr(foo, '_name_changed', False):
log.debug("foo changed its name from '%s' to '%s'",
foo._initial_name, foo.name)
您可以使用pre_save信号和比较的数据库记录(老版):
现在,你的“pre_save”或“post_save”信号处理程序上什么也 变化进行核对实例记录(已更新,但未保存在数据库版本中)。
采取示范像这样的为例:
class Person(models.Model):
Name = models.CharField(max_length=200)
在pre_save功能,您可以用分贝版本比较实例的版本 。
def check_person_before_saving(sender, **kwargs):
person_instance = kwargs['instance']
if person_instance.id:
# you are saving a Person that is already on the db
# now you can get the db old version of Person before the updating
# you should wrap this code on a try/except (just in case)
person_db = Person.objects.get(id=person_instance.id)
# do your compares between person_db and person_instance
...
# connect the signal to the function. You can use a decorator if you prefer
pre_save.connect(check_person_before_saving, sender=Person)
感谢您的回答。具体而言,还是非常普遍的,我想知道某个特定领域(例如选择领域)何时发生了变化。更进一步,我想按照你所说的做 - 在发生这种情况时发出定制信号。因此,回到我的问题 - 更新模型时,如何比较以前的值来发送此信号? (如果在post_save之前不保证该对象被保存,发出foo_has_updated信号似乎不正确,但未验证......但这完全是另一个问题)。 – 2010-07-09 20:56:02