Django 中的外键和保存方法

发布于 2024-12-03 16:28:15 字数 841 浏览 2 评论 0原文

我有以下模型:

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)

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

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

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

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

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

I have the following model :

class A:
  b = ForeignKey('B')

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

I have several methods that decode a json object and create a tree of objects A and B.
Suppose I have an object of type A that I want to save, I'm trying to write something like this

in class A :

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

in B :

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

This does not work, even though A.b and B.a get assigned an id while calling save(), it still violates the not null constraint in A.
I've read somewhere that this was due to how ORM works, and how the objects are cached somehow.

The solution proposed was to do something like this :

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

But for obvious reason of recursion, it's not appropriate in my case. So the only work around I can think of is to provide each objects with a method that recursively retrieve every object that need to be saved, and then do a for loop to save each one in the right order. I really would like to avoid this, since of course the actual model is more complex and involves more than two classes and more than one Foreign Key per class.

So I guess my question is simply : Is there a better way or a more common way to proceed in such situations ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撩起发的微风 2024-12-10 16:28:15

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

Well after some soul searching I found out that this was indeed a cache "problem". I don't have the time to look inside django code to understand how things really work, so if anyone have some interesting insights that would be great.

In the meantime, the solution I found is to force the object to clear its cache like this :

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

This does work, but for the record here is a little helper to automatically clear cache before any saving :

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)
稚气少女 2024-12-10 16:28:15

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

或者,使用保存后信号可能会更干净。

It's worth noting that you're doing the save of the other objects before you call the superclass save method, which is probably the opposite of what you want.

Alternatively, and this might end up being cleaner, use post-save signals.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文