我对删除发挥作用时OneToOneField的工作方式感到有些困惑。我能找到的唯一准权威信息来自this thread on django-developers:
我不知道你是否发现了这个,但删除工作正在进行中 一个方向,但不是你期望它的方向。对于 例如,使用您在另一条消息中发布的模型:
class Place(models.Model): name = models.CharField(max_length = 100) class Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True)
如果你 创建一个与其链接的地方和餐厅,删除 餐厅不会删除地方(这是你的问题 报告此处),但删除地方将删除餐厅。
我有以下型号:
class Person(models.Model):
name = models.CharField(max_length=50)
# ... etc ...
user = models.OneToOneField(User, related_name="person", null=True, blank=True)
这是以这种方式设置的,因此我可以使用person
从User
实例轻松访问user.person
。
然而,当我尝试删除管理员中的User
记录时,它自然会向后传递到我的Person
模型,就像讨论的主题一样,显示了以下内容:
您确定要删除用户“JordanReiter2”吗?以下所有相关项目都将被删除:
不用说我不想要删除Person
记录或其任何后代!
我想我理解逻辑:因为Person记录中的OneToOne字段中有一个值,删除User记录会在数据库的user_id
列中创建一个错误的引用。
通常,解决方案是切换OneToOne
字段所在的位置。当然,这并不现实,因为User
对象几乎由django.contrib.auth
设置。
是否有任何方法可以阻止删除级联,同时仍然可以通过简单的方式从user
访问此人? 仅方式是否可以创建扩展User
版本的django.contrib
模型?
我改变了模型名称,所以希望现在它更清晰了。基本上,有成千上万的人事记录。不是每个人都有登录,但如果他们这样做,他们只有一个登录。
答案 0 :(得分:23)
原来你可以将ForeignKey
and OneToOneField
have an attribute on_delete
设置为models.SET_NULL
,如下所示:
class Person(models.Model):
name = models.CharField(max_length=50)
# ... etc ...
user = models.OneToOneField(User, on_delete=models.SET_NULL, related_name="person", null=True, blank=True)
这会导致我想要的行为:删除User
模型而不触及Person
记录。我忽略了它,因为它没有在OneToOneField
下明确列出,只是说
此外,OneToOneField接受ForeignKey接受的所有额外参数......
容易错过。
答案 1 :(得分:0)
对于此用例,您应该使用简单的ForeignKey。 OneToOne意味着有一个,只能是一个,它只能与这一个特定的其他对象相关联。删除的原因是因为有一个空的onetoone字段是没有意义的,它不能与其他任何东西相关联。