问题
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