我们假设我们有以下模型。
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等等。
答案 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 ......这很疯狂。