Django OneToOneField - 我应该把它放在哪个模型中?

时间:2012-03-21 07:47:44

标签: django one-to-one

我们假设我们有以下模型。

class A(Model): pass
class B(Model): pass

然后没有区别:

在模型A中:b = OneToOneField(B, related_name=A.__name__)

模型B中的

a = OneToOneField(A, related_name=B.__name__)

那么我应该问自己什么问题来决定是否将OTO放在一个或另一个模型中。我的意思是像has-a,is-a等等。

4 个答案:

答案 0 :(得分:25)

实际上,放置一对一字段的位置存在差异,因为删除行为有所不同。删除对象时,将删除引用该对象的具有一对一关系的任何其他对象。相反,如果你删除一个包含一对一字段的对象(即它引用其他对象,但其他对象没有引用它),则不会删除其他对象。

例如:

class A(models.Model):
    pass

class B(models.Model):
    a = models.OneToOneField(A)

如果删除A,默认情况下B也会被删除(尽管你可以通过修改OneToOneField上的on_delete参数来覆盖它,就像使用ForeignKey一样)。删除B不会删除A(尽管您可以通过覆盖B)上的delete()方法来更改此行为。

回到你的初始问题has-a vs. is-a,如果A有B,B应该有一对一的字段(B应该仅在A存在时存在,但A可以存在而不存在B )。

答案 1 :(得分:8)

OneToOneField实际上仅用于两个目的:1)继承(Django使用它们来实现MTI)或2)扩展不可编辑的模型(比如为{{1创建UserProfile }})。

在这两种情况下,很明显User继续使用哪种模式。在继承的情况下,它继续在孩子身上。在扩展的情况下,它是您可以访问的唯一模型。

使用非常的例外情况,任何其他一对一的使用都应该真正合并到一个模型中。

答案 2 :(得分:1)

我认为OneToOne字段的情况,正确答案是无关紧要,它只取决于哪个模型与另一个模型相关更有意义。

答案 3 :(得分:0)

顺便说一下,我需要OneToOneField来防止循环依赖(继承使用):

Model A:
  ...
  current_choice = models.ForeignKey(B)

Model B:
  ...
  parent = models.ForeignKey(A)

这意味着,A需要定义B.引导不是一个好的数据库约定。 相反,我做了:

Model A:
  ...

Model B:
  ...
  parent = models.ForeignKey(A)

Model C:
  parent = models.OneToOneField(A)
  current_choice = models.ForeignKey(B)

关于来自documentation的示例,您还可以拥有干净的查询,例如:p1.restaurant.place.restaurant.place ......这很疯狂。