与用户模型(django.contrib.auth)的一对一关系,无需级联删除

发布于 2024-11-27 23:22:16 字数 1642 浏览 2 评论 0原文

我对删除发挥作用时 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.personUser 实例轻松访问 person

但是,当我尝试删除管理中的 User 记录时,它自然会向后级联到我的 Person 模型,正如线程所讨论的那样,显示以下内容

:您确定要删除用户“JordanReiter2”吗?以下所有相关项目都将被删除:

  • 用户:JordanReiter
    • 人物:JordanReiter
      • 提交内容:标题1
      • 提交内容:标题2

不用说,我不想想要删除 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

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 技术交流群。

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

发布评论

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

评论(2

暖伴 2024-12-04 23:22:16

事实证明 ForeignKeyOneToOneField 有一个属性 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 接受的所有额外参数...

很容易错过。

Turns out that both ForeignKey and OneToOneField have an attribute on_delete that you can set to models.SET_NULL, like so:

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)

This results in the behavior I was wanting: the User model is deleted without touching the Person record. I overlooked it because it's not explicitly listed under OneToOneField, it simply says

Additionally, OneToOneField accepts all of the extra arguments accepted by ForeignKey...

Easy to miss.

仅一夜美梦 2024-12-04 23:22:16

对于此用例,您应该使用简单的外键。 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.

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