Django:扩展User时,最好使用OneToOneField(User)或ForeignKey(User,unique = True)?

时间:2010-07-11 03:25:47

标签: django django-models django-users django-profiles

通过扩展Django用户模型,在创建OneToOneField(User)模型时,我发现有关是否使用ForeignKey(User, unique=True)UserProfile的信息存在冲突。

使用它更好吗?:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)

或者这个?:

class UserProfile(models.Model):
    user = models.OneToOneField(User)

Django Doc指定OneToOneField,而Django Book example使用ForeignKey

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

在前一篇文章中,Bennett提供了一些理由说明为什么他转而使用ForeignKey代替OneToOneField,但我不太明白,特别是当我看到其他帖子推荐相反的情况时。

我很想知道你的偏好和原因。或者,它甚至重要吗?

3 个答案:

答案 0 :(得分:18)

文章中给出的唯一真正原因是可以对其进行设置,以便User的管理页面同时显示UserUserProfile中的字段。这可以用OneToOneField复制一点点肘部油脂,所以除非你沉迷于在管理页面中显示它而不需要花费一些清晰度(“我们可以为每个用户创建多个配置文件) ?!哦不,等等,这是独一无二的。“)我会使用OneToOneField

答案 1 :(得分:7)

除了管理页面内联之外,ForeignKey解决方案的其他原因是它允许您在以反向关系访问对象时使用正确的默认数据库管理器。考虑这个subclasses manager snippet的例子。假设示例中的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],您可以获得所需的Post类的子类对象,方法是将第一个(默认)管理器定义为ChildManager。另一方面,使用OneToOneField,通过调用somemodel_instance.post,您将获得Post类实例。您始终可以调用somemodel_instance.post.subclass_object并获得相同的结果,但默认管理器可以执行任何其他类型的操作,而FK解决方案可以很好地隐藏它们。

如果您拥有并且可以修改自定义管理器代码,则可以使用use_for_related_fields属性而不是使用FK代替合法的1to1字段,但即使这样也会失败,因为我不知道的一些令人讨厌的问题。自动经理。据我记得,在上面的例子中它会失败。

答案 2 :(得分:5)

通常不使用与反向关系相关的OneToOneField的其他原因:当您使用通过OneToOneField定义的反向关系时,您会得到一个模型实例,与Manager相对于ForeignKey反向关系,因此总是有数据库命中。如果你在反向关系上做一些通用的东西(通过_meta.get_all_related_objects())并且不知道和关心你是否全部使用它们,这是很昂贵的。