2010-07-09 92 views

回答

7

model validation

注意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>) 

和你有你需要的东西(我认为)!!!

+0

感谢您的回答。具体而言,还是非常普遍的,我想知道某个特定领域(例如选择领域)何时发生了变化。更进一步,我想按照你所说的做 - 在发生这种情况时发出定制信号。因此,回到我的问题 - 更新模型时,如何比较以前的值来发送此信号? (如果在post_save之前不保证该对象被保存,发出foo_has_updated信号似乎不正确,但未验证......但这完全是另一个问题)。 – 2010-07-09 20:56:02

0

保存前,您可以询问数据库中当前存储的值。我这样做只记录更改的值,但每次保存时都会导致另一个数据库查询。

0

虽然我非常赞同Sébastien Piquemal's answer我最终最终同时使用了pre_savepost_save信号。我不是重写__init__(),而是在pre_save中做了非常类似的事情,然后检查/比较post_save中的值,并在满足某些条件时从那里发出自定义信号。

我想我仍然会接受他的答案,花在它上面的时间。我没有看到我们在做什么与众不同,除了我正在做一个信号的工作,而他正在做初始化工作。

2

这里是我的想法:玩弄性质

说你有这个类:

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) 
0

您可以使用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) 
相关问题