Fork me on GitHub

The Django model field API provides a ForeignKey [Django-doc] and a OneToOneField [Django-doc]. Both fields share most of the same parameters: in fact a OneToOneField is a subclass of a ForeignKey. In the constructor, it sets the unique=… parameter [Django-doc] to True. If you create a ForeignKey with unique=True, then Django will raise an warning that explains that a OneToOneField is probably more appropriate. The fact that a OneToOneField is unique means thus that for two records, the OneToOneFields can not refer to the same record.

As a result if a Profile has a OneToOneField to a User model, it means that two Profiles can not refer to the same User, and thus a User record has at most one related Profile. This is important: it means that if we access the Profile(s) of a User we get zero or one records. As a result the designers of Django specified the related_name=… [Django-doc] of a OneToOneField, not as modelname_set, but modelname. Indeed, you access the Profile that belongs to a User object my_user with my_user.profile (given you do not override the related_name=… parameter). This will look for a Profile object, and returns that object if it can be found, otherwise it raises a RelatedObjectDoesNotExist exception. For a ForeignKey, the default would have been profile_set, and my_user.profile_set is a RelatedManager [Django-doc]: accessing this attribute would thus never raise an error, and one can then access all the related Profiles with my_user.profile_set.all().

A OneToOneField is also used for inheritance. If one has a concrete model named Vehicle, and a subclass of that model named Car, then Django will add a "hidden" OneToOneField named modename_ptr with modelname the name of the model of the parent in lowercase, so in this case, it will be vehicle_ptr. One might want to provide a field themselves, for example to give this a different name, or to add certain behavior. Therefore a OneToOneField accepts an extra .parent_link=… parameter [Django-doc] which is a boolean that can be set to True in case the OneToOneField acts as a link to that parent.

The OneToOneField often gives the wrong impression that if a model Profile has a OneToOneField to a User model for example, it somehow would guarantee that a user has exactly one Profile. That is not the case: a OneToOneField guarantees, if it is not null=True, that a Profile has exactly one related User model, and a User has at most one related Profile. It thus will not automatically create a Profile object in case a User object is constructed. Perhaps a more appropriate name might have been an OptionalToOneField.

Summary

ForeignKeyOneToOneField
relation typemany-to-oneoptional-to-one
uniquenessnot unique (unless specified)always unique
default related_namemodelname_setmodelname
related relationRelatedManagertrying to fetch the reverse object
parametersextra parent_link=…