【问题标题】:OneToOne relation with the User model (django.contrib.auth) without cascading delete与用户模型 (django.contrib.auth) 的 OneToOne 关系,没有级联删除
【发布时间】:2011-10-21 06:03:13
【问题描述】:

当删除开始起作用时,我对 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)  

如果你 创建一个地方和与其链接的餐厅,删除 餐厅不会删除 Place(这是您遇到的问题 在此处报告),但删除地方会删除餐厅。

我有以下型号:

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

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

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

  • 用户:JordanReiter
    • 人:JordanReiter
      • 提交:Title1
      • 提交:Title2

不用说我确实想要删除Person 记录或其任何后代!

我想我理解其中的逻辑:因为在 Person 记录的 OneToOne 字段中有一个值,所以删除 User 记录会在数据库的 user_id 列中创建一个错误的引用。

通常,解决方案是切换OneToOne 字段所在的位置。当然,这是不可能的,因为User 对象几乎是由django.contrib.auth 设置的。

有什么方法可以防止删除级联,同时仍然可以直接从user 访问人员?创建扩展django.contrib 版本的User 模型是唯一 方法吗?

更新

我更改了型号名称,希望现在它更清晰一点。基本上,有数以千计的 Person 记录。不是每个人都有登录名,但如果有,他们只有一个登录名。

【问题讨论】:

    标签: django django-authentication one-to-one cascading-deletes


    【解决方案1】:

    原来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 接受的所有额外参数...

    很容易错过。

    【讨论】:

    • 嗨乔丹,我一直在寻找一个简单问题的解决方案:删除级联行为是否仅适用于多对一字段或单对一字段。在 Django 文档中,他们只在 ManyToOne 字段中提到它。对于您的问题,我了解到在删除对象时,OneToOne 关系的行为与 ManyToOne 完全相同。您能确认一下吗?
    • 没有ManyToOne字段;只是 ForeignKey 字段。正如我所指出的,OneToOneField 接受所有与 ForeignKey 相同的参数。我认为 OneToOneField 在实现上与 ForeignKey 字段基本相同,除了坚持一个相关记录而不是很多。关系数据库中实际上并不存在一对一(尽管您可以有强制执行它的约束);它只是在 Django 中以编程方式实现的。
    • 非常感谢乔丹提供的信息。抱歉打错了,我想说的是多对一关系。
    • 这些由 ForeignKey 字段处理。
    【解决方案2】:

    对于这个用例,您应该使用一个简单的 ForeignKey。 OneToOne 表示只有一个,并且只能是一个,并且只能与这个特定的其他对象相关联。发生删除是因为拥有一个空的 onetoone 字段没有意义,它不能与其他任何内容相关联。

    【讨论】:

    • 除非这表明多个Foo 可以绑定到单个用户,但事实并非如此。考虑一个案例,您有一个学校的个人数据库。其中一些有登录名,而另一些则没有。但是没有一个登录与多个人相关联的情况。实际上,你知道吗,让我改变一下我的例子,这样更清楚。
    • 您可以将 ForeignKey 与 unique=True 一起使用。这仍然意味着您需要通过 User.person_set.get() 访问,但会防止重复。
    • Matthew 说了什么 :-) 也许只有我一个人,但我认为 OneToOne 有一个,而且总是有一个;双向的。如果它是可选的但唯一的,我将 ForeignKey 与 unique-True 一起使用。
    • 我想我一直在想这样的一对一:如果对象 A 有一个一对一指向对象 B,这意味着对象 A 可能有一个对象 B(如果一对一允许为NULL)。我猜另一种解释是,如果对象 A 与 B 是一对一的,那么实际上 B 可能会或可能不会将对象 A 附加到 it。我想我明白了,因为 A.ForeignKey -> B 意味着 B 可能有一个或多个 As 附加在它上面。有道理,但为简单起见,我坚持使用 OneToOne
    猜你喜欢
    • 1970-01-01
    • 2017-11-17
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2011-05-08
    相关资源
    最近更新 更多