与用户模型(django.contrib.auth)的一对一关系,无需级联删除
我对删除发挥作用时 OneToOneField 的工作原理有点困惑。我能找到的唯一准权威信息来自 django-developers 上的这个帖子:
我不知道你是否发现了这一点,但删除正在起作用 一个方向,但不是您期望的方向。为了 例如,使用您在另一条消息中发布的模型:
类 Place(models.Model): 名称 = models.CharField(max_length = 100) 餐厅类(模型.模型): 地点 = 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)
它是这样设置的,因此我可以使用 user.person
从 User
实例轻松访问 person
。
但是,当我尝试删除管理中的 User
记录时,它自然会向后级联到我的 Person
模型,正如线程所讨论的那样,显示以下内容
:您确定要删除用户“JordanReiter2”吗?以下所有相关项目都将被删除:
- 用户:JordanReiter
- 人物:JordanReiter
- 提交内容:标题1
- 提交内容:标题2
- 人物:JordanReiter
不用说,我不想想要删除 Person
记录或其任何后代!
我想我理解这个逻辑:因为 Person 记录的 OneToOne 字段中有一个值,删除 User 记录会在数据库的 user_id
列中创建错误的引用。
通常,解决方案是切换 OneToOne
字段所在的位置。当然,这实际上是不可能的,因为 User
对象几乎是由 django.contrib.auth
设置的。
有没有什么方法可以防止删除级联,同时仍然可以通过 user
直接访问人员?创建扩展 django.contrib
版本的 User
模型是唯一方法吗?
更新
我更改了模型名称,希望现在更清晰一些。基本上,有数千条人员记录。并非每个人都有登录名,但即使有,他们也只有一个登录名。
I'm a bit confused about how the OneToOneField works when deletion comes into play. The only quasi-authoritative info I can find is from this thread on django-developers:
I don't know if you discovered this yet, but the delete is working in
one direction, but not in the direction you're expecting it to. For
instance, using the models you posted in another message:class Place(models.Model): name = models.CharField(max_length = 100) class Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True)
If you
create a Place and a Restaurant that is linked to it, deleting the
Restaurant will not delete the Place (this is the problem you're
reporting here), but deleting the Place will delete the Restaurant.
I have the following model:
class Person(models.Model):
name = models.CharField(max_length=50)
# ... etc ...
user = models.OneToOneField(User, related_name="person", null=True, blank=True)
It's set up this way so I can easily access person
from a User
instance using user.person
.
However, when I try to delete a User
record in admin, naturally it's cascading backwards to my Person
model, just as the thread discussed, showing something along the lines of:
Are you sure you want to delete the user "JordanReiter2"? All of the following related items will be deleted:
- User: JordanReiter
- Person: JordanReiter
- Submission: Title1
- Submission: Title2
- Person: JordanReiter
Needless to say I do not want to delete the Person
record or any of its descendants!
I guess I understand the logic: because there is a value in the OneToOne field in the Person record, deleting the User record would create a bad reference in the user_id
column in the database.
Normally, the solution would be to switch where the OneToOne
field is located. Of course, that's not realistically possible since the User
object is pretty much set by django.contrib.auth
.
Is there any way to prevent a deletion cascade while still having a straightforward way to access person from user
? Is the only way to do it creating a User
model that extends the django.contrib
version?
Update
I changed the model names so hopefully now it's a little clearer. Basically, there a thousands of Person records. Not every person has a login, but if they do, they have one and only one login.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
事实证明
ForeignKey
和OneToOneField
有一个属性on_delete
,您可以将其设置为models.SET_NULL
,如下所示:这会导致以下行为我想要:删除
User
模型而不触及Person
记录。我忽略了它,因为它没有明确列在OneToOneField
下,它只是说很容易错过。
Turns out that both
ForeignKey
andOneToOneField
have an attributeon_delete
that you can set tomodels.SET_NULL
, like so:This results in the behavior I was wanting: the
User
model is deleted without touching thePerson
record. I overlooked it because it's not explicitly listed underOneToOneField
, it simply saysEasy to miss.
对于此用例,您应该使用简单的外键。 OneToOne 意味着存在一个,并且只能是一个,并且它只能与这个特定的其他对象关联。发生删除是因为拥有空 onetoone 字段没有意义,它不能与其他任何内容关联。
For this use case you should use a simple ForeignKey. OneToOne means there is one, and can only be one and it can only be associated with this one specific other object. The deletion occurs because it doesn’t make sense to have a null onetoone field, it CAN'T be associated with anything else.