Django: When extending User, better to use OneToOneField(User) or ForeignKey(User, unique=True)?

廉价感情. 提交于 2019-12-28 08:11:43

问题


I'm finding conflicting information on whether to use OneToOneField(User) or ForeignKey(User, unique=True) when creating a UserProfile model by extending the Django User model.

Is it better to use this?:

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

or this?:

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

The Django Doc specifies OneToOneField, while the Django Book example uses ForeignKey.

James Bennett also has two Blog posts that providing conflicting examples as well:

  • Extending the User Model
  • User Registration

In the former post, Bennett provides some reasons why he switched to using ForeignKey instead of OneToOneField, but I don't quite get it, especially when I see other posts that recommend the opposite.

I'm curious to know your preference and why. Or, does it even matter?


回答1:


The only real reason given in the article is that it can be set up so that the admin page for User will show both the fields in User and UserProfile. This can be replicated with a OneToOneField with a little elbow grease, so unless you're addicted to showing it in the admin page with no work at the cost of a bit of clarity ("We can create multiple profiles per user?! Oh no, wait, it's set unique.") I'd use OneToOneField.




回答2:


Besides the admin page inlines, other reason for the ForeignKey solution is that it allows you to use the correct, default DB manager when objects are accessed with a reverse relation. Consider example from this subclasses manager snippet. Let's say that the Post class definition from the example looks like this:

class Post(ParentModel):
    title = models.CharField(max_length=50)
    onetoone = models.ForeignKey(SomeModel, unique=True)

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

By calling somemodel_instance.post_set.all()[0], you get the desired subclasses objects of the Post class as indicated by defining the first (default) manager as a ChildManager. On the other hand, with OneToOneField, by calling somemodel_instance.post you get the Post class instance. You can always call somemodel_instance.post.subclass_object and get the same result, but the default manager could do any other sort of tricks and the FK solutions hides them nicely.

If you own and can modify the custom manager code you can use the use_for_related_fields attribute instead of using FK in place of legitimate 1to1 field, but even that can fail because of some not-known to me nuisances of the automatic managers. As far as I remember it will fail in the above example.




回答3:


Other reason to generally not use the OneToOneField related to reverse relations: when you use reverse relations defined via OneToOneField you get an model instance, contrary to Manager for ForeignKey reverse relation and as a consequence there's always a DB hit. This is costly if you do some generic stuff on reverse relations (via _meta.get_all_related_objects()) and do not know and care if you will use them all or not.



来源:https://stackoverflow.com/questions/3221745/django-when-extending-user-better-to-use-onetoonefielduser-or-foreignkeyuse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!