Django中的外键和保存方法

时间:2011-09-10 18:35:29

标签: django recursion foreign-keys save

我有以下型号:

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中的not null约束。 我在某处读过这是因为ORM是如何工作的,以及如何以某种方式缓存对象。

建议的解决方案是做这样的事情:

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

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

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

2 个答案:

答案 0 :(得分:2)

经过深思熟虑,我发现这确实是一个缓存“问题”。我没有时间查看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)

答案 1 :(得分:0)

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

或者,这可能最终变得更清洁,使用post-save signals