【问题标题】:What is the best / proper idiom in django for modifying a field during a .save() where you need to old value?在 .save() 期间修改字段的最佳/正确习惯用法是什么?
【发布时间】:2011-02-08 21:59:48
【问题描述】:

说我有:

class LogModel(models.Model):
    message = models.CharField(max_length=512)

class Assignment(models.Model):
    someperson = models.ForeignKey(SomeOtherModel)
    def save(self, *args, **kwargs):
        super(Assignment, self).save()
        old_person = #?????
        LogModel(message="%s is no longer assigned to %s"%(old_person, self).save()
        LogModel(message="%s is now assigned to %s"%(self.someperson, self).save()

我的目标是向 LogModel 保存一些关于分配被分配给谁的消息。请注意,我需要知道该字段的旧值。

我看到代码建议,在 super().save() 之前,通过主键从数据库中检索实例并从那里获取旧值。这可以工作,但有点混乱。

此外,我计划最终通过信号将这段代码从 .save() 方法中分离出来——即 pre_save() 和 post_save()。尝试使用上述逻辑(从 pre_save 中的数据库检索,在 post_save 中创建日志条目)在这里似乎失败,因为 pre_save 和 post_save 是两个单独的方法。也许在 pre_save 中我可以检索旧值并将其作为属性粘贴到模型上?

我想知道这是否有一个常见的成语。谢谢。

【问题讨论】:

    标签: django orm signals models


    【解决方案1】:

    几个月前,我在网上的某个地方找到了一个很好的方法......

    class YourModel(models.Model):
    
        def __init__(self, *args, **kwargs):
            super(YourModel, self).__init__(*args, **kwargs)
            self.original = {}
            id = getattr(self, 'id', None)
    
            for field in self._meta.fields:
                if id:
                    self.original[field.name] = getattr(self, field.name, None)
                else:
                    self.original[field.name] = None
    

    基本上,模型字段的副本将保存到 self.original。然后您可以在模型的其他位置访问它...

    def save(self, *args, **kwargs):
        if self.original['my_property'] != self.my_property:
            # ...
    

    【讨论】:

      【解决方案2】:

      使用signals 可以轻松完成。每个 Django 模型分别有一个 pre-savepost-save 信号。

      【讨论】:

      • 我知道,但您没有回答关于将旧值保持在两者之间的问题。此外,如果再做一次 db hit 确实是保持旧值的正确方法。
      【解决方案3】:

      所以我想出了这个:

      class LogModel(models.Model):
          message = models.CharField(max_length=512)
      
      class Assignment(models.Model):
          someperson = models.ForeignKey(SomeOtherModel)
      
      import weakref
      _save_magic = weakref.WeakKeyDictionary()
      
      @connect(pre_save, Assignment)
      def Assignment_presave(sender, instance, **kwargs):
          if instance.pk:
              _save_magic[instance] = Assignment.objects.get(pk=instance.pk).someperson
      
      @connect(post_save, Assignment)
      def Assignment_postsave(sender, instance, **kwargs):
          old = None
          if instance in _save_magic:
              old = _save_magic[instance]
              del _save_magic[instance]
              LogModel(message="%s is no longer assigned to %s"%(old, self).save()
          LogModel(message="%s is now assigned to %s"%(instance.someperson, self).save()
      

      StackOverflow 是怎么想的?有更好的吗?有什么建议吗?

      【讨论】:

      • PS:@connect 是一个自定义装饰器,它只做 signal.connect(f, sender=self.sender)
      猜你喜欢
      • 1970-01-01
      • 2017-08-13
      • 2013-06-05
      • 2016-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2010-10-05
      相关资源
      最近更新 更多