BudiBadu Logo
Samplebadu

Django by Example: One To One Mapping

Django 5.0+

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

7
models.OneToOneField defines the relationship. Like ForeignKey, it requires a target model and an on_delete behavior.
10
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.
11
related_name='profile' allows us to access the profile via user.profile. If not set, the default would be user.userprofile.
299
models.ImageField requires the Pillow library. The upload_to argument specifies the subdirectory within your MEDIA_ROOT where uploaded files will be stored.