Django:在扩展User时,是更好地使用OneToOneField(User)还是ForeignKey(User,unique = True)?

30

我在寻找有关在扩展Django User模型创建UserProfile模型时,是使用OneToOneField(User)还是ForeignKey(User, unique=True)的矛盾信息。

哪种方法更好?:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
或者这样做?
class UserProfile(models.Model):
    user = models.OneToOneField(User)

Django文档使用OneToOneField,而Django书籍示例使用ForeignKey

James Bennett也有两篇博客文章提供了相互矛盾的示例:

在前一篇文章中,Bennett提供了一些原因,解释为什么他改用ForeignKey而不是OneToOneField,但我并不太明白,尤其是当我看到其他文章推荐相反的时候。

我想知道你的偏好以及原因。或者说,这真的重要吗?


在Bennett的第一篇文章中,我没有看到有关用户配置文件的内容。 - Ignacio Vazquez-Abrams
@Ignacio - 对不起,我给出了错误的链接。应该是指他在“扩展用户模型”一文中的帖子。我已经更正了链接。感谢你指出这个问题。 - Tony Guinta
对我来说,https://dev59.com/UW025IYBdhLWcg3wqn4N 更容易理解。 - Chemical Programmer
3个回答

21

这篇文章唯一给出的理由是,使用User模型中的字段和UserProfile模型中的字段都能在User的管理页面中显示。如果想要实现这个效果,可以借助OneToOneField并稍加努力。因此,除非你沉迷于不费吹灰之力就能将它们同时显示在管理页面,即使这会牺牲一些清晰度("我们可以为一个用户创建多个档案?哦,不对,设置了唯一性。"),否则我建议使用OneToOneField


7
除了管理页面内联之外,使用ForeignKey解决方案的另一个原因是当使用反向关系访问对象时,它允许您使用正确的默认DB管理器。考虑一下来自子类管理器片段的示例。假设示例中的Post类定义如下:
class Post(ParentModel):
    title = models.CharField(max_length=50)
    onetoone = models.ForeignKey(SomeModel, unique=True)

    children = ChildManager()
    objects = models.Manager()

通过调用 somemodel_instance.post_set.all()[0],您可以获得由定义第一个(默认)管理器为 ChildManager 所指示的 Post 类所需的子类对象。另一方面,使用 OneToOneField,通过调用 somemodel_instance.post,您可以获得 Post 类实例。您始终可以调用 somemodel_instance.post.subclass_object 并获得相同的结果,但是默认管理器可以执行任何其他类型的技巧,而 FK 解决方案则将其隐藏得很好。
如果您拥有并且可以修改自定义管理器代码,则可以使用 use_for_related_fields 属性代替在合法的 1to1 字段位置使用 FK,但即使如此,由于自动管理器的某些我不知道的麻烦,它也可能失败。据我所记,它将在上面的示例中失败。

5

不要使用OneToOneField来定义反向关系的另一个原因是:当您使用通过OneToOneField定义的反向关系时,您将得到一个模型实例,与ForeignKey反向关系的Manager相反,因此始终会有一个数据库查询。如果您在反向关系上执行一些通用操作(例如通过_meta.get_all_related_objects()),并且不知道也不关心是否会使用它们全部,这将很耗费时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接