Difference between One-to-one, Many-to-many, and Many-to-one Relationships in Django

Muhammed Ali
Analytics Vidhya
Published in
4 min readMar 31, 2021

You can’t successfully build a project with Django without learning how to use the 3 relationships in Django.

When I started learning Django, I had a problem with figuring out the use cases of the relationships. Well, if you are having such a problem, stick around while we go through how to use the relationships in Django.
To follow along with this tutorial should at least be familiar with models in Django and their usefulness. Now, let’s hop in!

One-to-one Relationship

In a one-to-one relationship, two models are related in such a way that each record in one model is associated with one and only one record in the other model, and vice versa. However, these two models remain separate entities with their own attributes and fields. The primary purpose of a one-to-one relationship is typically to create an optional, one-to-one connection between two models, not to inherit all properties. It is essentially there, so you don’t replicate fields in one model in another model.

Let’s say you are building an app for students. Here we can have two models Student and StudentProfile. The StudentProfile model will have additional fields beyond what's in the Student model, and it is linked to the Student model through a one-to-one relationship. This allows for storing additional information specific to a student's profile without duplicating all the attributes of the Student model.

from django.db import models

class Student(models.Model):
# Basic information about the student
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField()
email = models.EmailField(unique=True)

# Additional fields can be added as needed
# For example: address, phone number, etc.

def __str__(self):
return f"{self.first_name} {self.last_name}"

class StudentProfile(models.Model):
# Link the profile to a student
student = models.OneToOneField(Student, on_delete=models.CASCADE)

# Additional information about the student
bio = models.TextField(blank=True)
profile_image = models.ImageField(upload_to='profile_images/', blank=True, null=True)
social_media_profile = models.URLField(max_length=200, blank=True)

# Additional fields can be added as needed to store more details about the student's profile

def __str__(self):
return f"Profile for {self.student.first_name} {self.student.last_name}"

In this example, we have a Student model with basic information such as the student's first name, last name, date of birth, and email. You can add more fields like address, phone number, or any other relevant information.

The StudentProfile model is linked to the Student model using a one-to-one relationship, meaning that each student can have one and only one profile. The StudentProfile model includes additional information like a biography, profile image, and a link to the student's social media profile.

Many-to-many Relationship

In many-to-many relationships, zero or more objects in one model can be related to zero or more objects in another model, yeah, it’s that simple. Here’s another example of a many-to-many relationship in Django using a simplified social media application. We’ll create models for User and Group, where users can be part of multiple groups, and groups can have multiple members.

from django.db import models

class User(models.Model):
username = models.CharField(max_length=50, unique=True)
full_name = models.CharField(max_length=100)

# Define a many-to-many relationship with Group
groups = models.ManyToManyField('Group', related_name='members')

def __str__(self):
return self.username

class Group(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField()

def __str__(self):
return self.name

The User model has a many-to-many relationship with the Group model through the groups field. The related_name='members' attribute is added to the groups field. This means that from the User model, you can use the members attribute to access the related Group objects that the user is a member of.

The Group model doesn't specify a related_name, which means that from the Group model, you can use the default reverse relationship name, which is automatically generated based on the model name in lowercase. In this case, you can access the related User objects from the Group model using the lowercased model name, i.e., user_set.

Here’s how you can use the related_name and default reverse relationship to access related objects:

# Creating users
user1 = User.objects.create(username="alice", full_name="Alice Johnson")
user2 = User.objects.create(username="bob", full_name="Bob Smith")

# Creating groups and associating members
group1 = Group.objects.create(name="Developers", description="A group for software developers")
group1.members.add(user1, user2)

group2 = Group.objects.create(name="Designers", description="A group for graphic designers")
group2.members.add(user1)

# Accessing groups of a user using the related_name
groups_of_user1 = user1.groups.all()

# Accessing members of a group using the default reverse relationship name
members_of_group1 = group1.user_set.all()

Many-to-one Relationships

The many-to-one relationship is known as a foreign key relationship in Django, where one object in one model may be related to one or more objects in another model. Multiple projects can be assigned to one student. In this example, we will compare the relationship between two entities, Student and Project. The source model (containing the foreign key) is considered the “many” side, and the target model (being referred to by the foreign key) is the “one” side of the relationship.

class Student(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)

def __str__(self):
return self.first_name

class Project(models.Model):
name = models.CharField(max_length=30)
# Define a foreign key relationship with Student
students = models.ForeignKey(Student, on_delete=models.CASCADE)
def __str__(self):
return self.name

The Student model represents students with first_name and last_name fields. The Project model represents projects with a name field. It also has a foreign key relationship with the Student model through the student field. This means that one or more projects can be associated with one student.

Now, you can access related objects as follows:

# Creating a student
student1 = Student.objects.create(first_name="John", last_name="Doe")

# Creating projects associated with the student
project1 = Project.objects.create(name="Project A", student=student1)
project2 = Project.objects.create(name="Project B", student=student1)

# Accessing projects of a student
projects_of_student1 = student1.project_set.all()

# Accessing the student of a project
student_of_project1 = project1.student

Conclusion

Understanding these relationships and when to use them is crucial for designing and building robust Django applications. Each type of relationship serves specific use cases and provides the necessary flexibility to model complex data structures effectively. Hopefully, with this article, you will know which of them to utilize in your project.

--

--

Muhammed Ali
Analytics Vidhya

Technical Writer with experience in building awesome stuff with Django, Python, JavaScript, React, Kubernetes, etc. || Cloud-Native enthusiast.