Django by Example: One To One Mapping
A One-to-One relationship is essentially a ForeignKey with a unique constraint. This code example shows how it is commonly used to extend existing models (like the built-in User model) with additional information.
Code
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
# OneToOneField creates a unique link to the User model.
# Each User can have only one Profile, and each Profile belongs to one User.
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=True, # Optional: makes this field the PK
related_name='profile'
)
bio = models.TextField(blank=True)
birth_date = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='avatars/', null=True)
def __str__(self):
return f"Profile for {self.user.username}"
# Usage:
# user = User.objects.create(username='alice')
# profile = UserProfile.objects.create(user=user, bio='Developer')
#
# Accessing the profile from user:
# print(user.profile.bio) # Output: Developer
#
# Accessing user from profile:
# print(profile.user.username) # Output: alice
#
# Error:
# UserProfile.objects.create(user=user) # Raises IntegrityError (UniqueConstraint)Explanation
A OneToOneField is conceptually similar to a ForeignKey with unique=True, but it carries a distinct semantic meaning: it represents a strict 1:1 relationship where each record in the source table corresponds to exactly one record in the target table. This is widely used for "extending" models without inheritance, such as creating a UserProfile to store additional data for the built-in User model.
The primary difference lies in the reverse relationship API. With a standard ForeignKey, the reverse accessor returns a QuerySet (e.g., user.book_set.all()). In contrast, a OneToOneField's reverse accessor returns a single object directly (e.g., user.profile). If the related object does not exist, accessing this property raises a DoesNotExist exception, which you must handle in your code.
Internally, this field is also the mechanism Django uses to implement Multi-Table Inheritance. When a child model inherits from a parent model (that is not abstract), Django implicitly creates a OneToOneField linking the child back to the parent, ensuring that the child instance can access all fields from the parent table transparently.
Code Breakdown
models.OneToOneField defines the relationship. Like ForeignKey, it requires a target model and an on_delete behavior.primary_key=True is an optimization. It tells Django to use the 'user_id' column as both the foreign key AND the primary key of the UserProfile table, avoiding the creation of a separate 'id' column.related_name='profile' allows us to access the profile via user.profile. If not set, the default would be user.userprofile.models.ImageField requires the Pillow library. The upload_to argument specifies the subdirectory within your MEDIA_ROOT where uploaded files will be stored.
