【问题标题】:Foreign keys and save method in DjangoDjango中的外键和保存方法
【发布时间】:2011-11-14 11:37:25
【问题描述】:

我有以下型号:

class A:
  b = ForeignKey('B')

class B:
  a = ForeignKey('A', null=True)

我有几种方法可以解码 json 对象并创建对象 A 和 B 的树。 假设我有一个 A 类型的对象要保存,我正在尝试写这样的东西

在 A 类中:

def save(self, *args, **kwargs):
  self.b.save()
  super(A, self).save(*args, **kwargs)

在 B 中:

def save(self, *args, **kwargs):
  if self.a:
    self.a.save()
  super(B, self).save(*args, **kwargs)

这不起作用,即使 A.b 和 B.a 在调用 save() 时被分配了一个 id,它仍然违反了 A 中的非空约束。 我在某处读到,这是由于 ORM 的工作原理以及对象是如何以某种方式缓存的。

提出的解决方案是这样做:

a = A()
b = B()
b.save()
a.b = b
a.save()

但是由于递归的明显原因,这对我来说是不合适的。所以我能想到的唯一解决方法是为每个对象提供一个递归检索每个需要保存的对象的方法,然后执行一个 for 循环以正确的顺序保存每个对象。我真的很想避免这种情况,因为实际模型当然更复杂,并且涉及两个以上的类和每个类多个外键。

所以我想我的问题很简单:在这种情况下是否有更好的方法或更常见的方法?

【问题讨论】:

    标签: django recursion foreign-keys save


    【解决方案1】:

    经过一番深思熟虑,我发现这确实是一个缓存“问题”。我没有时间查看 django 代码来了解事情的真正运作方式,所以如果有人有一些有趣的见解,那就太好了。

    与此同时,我找到的解决方案是像这样强制对象清除其缓存:

    def save(self, *args, **kwargs):
      self.b.save()
      self.b = self.b # yes ...
      super(A, self).save(*args, **kwargs)
    

    这确实有效,但这里记录的是在任何保存之前自动清除缓存的小帮手:

    def clear_cache(obj):
      map(lambda x: obj.__setattr__(x, obj.__getattribute__(x)), \ # force reassignment
        map(lambda x: re.match('_(.*)_cache', x).groups()[0], \    # get attribute name
        filter(lambda x: x.find('_cache') != -1, dir(obj))))       # get all attribute with cache
    
    @receiver(pre_save)
    def cache_callback(sender, instance, **kwargs):
      clear_cache(instance)
    

    【讨论】:

      【解决方案2】:

      值得注意的是,您在调用超类保存方法之前保存了其他对象,这可能与您想要的相反。

      或者,这可能会更干净,使用post-save signals

      【讨论】:

      • 这取决于您首先保存哪个对象,实际上在我的情况下两者都可能发生,但如果我能解决这个问题,那就太好了。
      • Oups enter 发送了评论...这是正确的顺序,因为当我保存 A 时,我希望外键有效,因此我必须先保存它。所以在我的情况下,我应该使用预保存信号,我尝试过它仍然给我非空约束错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-26
      • 2017-11-16
      • 2017-05-10
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      • 2013-08-23
      相关资源
      最近更新 更多