DEV Community

Cover image for ForeignKey vs ManyToMany vs OneToOne: When to Use Each in Django
Ezeana Micheal
Ezeana Micheal

Posted on

ForeignKey vs ManyToMany vs OneToOne: When to Use Each in Django

In common Relational Database concepts, relationships between tables are nothing new; these help to represent connections between tables and link them together. In this article, I’ll explore some common DB relationships and how they are used in Django. These include One-to-One, One-to-Many (foreign key), and Many-to-Many Relationships.

One to One

In a one-to-one relationship, one record in a model corresponds exactly to one record in another model. For example, a user’s relationship to his profile, using Django’s built-in user model, we can extend by creating a user profile:

from django.contrib.auth.models import User

class Profile(models.Model):  
    user = models.OneToOneField(User, on_delete=models.CASCADE)  
    bio = models.TextField()  
    birth_date = models.DateField(null=True, blank=True)

Enter fullscreen mode Exit fullscreen mode

One to Many

In a one-to-many relationship, one record in a model corresponds to many records in another model. This means a record in a table can be linked to multiple records in another table, and this is done using a foreign key. A practical example of this is of an author having many books.

from django.db import models

class Author(models.Model):  
    name = models.CharField(max_length=100)

class Book(models.Model):  
    title = models.CharField(max_length=200)  
    author = models.ForeignKey(Author, on_delete=models.CASCADE)  
Enter fullscreen mode Exit fullscreen mode

Many to Many

In a many-to-many relationship, a table is linked to another table where multiple records in one table are related to various records in the other. An example is a relationship between students and courses. A student can enroll in many courses, and a course can have many students.

class Student(models.Model):  
    name = models.CharField(max_length=100)

class Course(models.Model):  
    title = models.CharField(max_length=200)  
    students = models.ManyToManyField(Student)

Enter fullscreen mode Exit fullscreen mode

In each of these types of relationships in Django, there are some common parameters and their meaning.

  1. On_delete: In a foreign key and the one-to-one field, there’s the on_delete parameter.

The common options are:

  1. models.CASCADE: delete related objects too.
  2. models.SET_NULL: set field to NULL (requires null=True).
  3. models.PROTECT: prevent deletion if related objects exist.
  4. models.SET_DEFAULT: set field to default value.
  5. Related_name: This defines the name used to access the reverse relationship; without this, Django automatically adds _set, i.e, (model_name)_set.
   class Course(models.Model):  
       title = models.CharField(max_length=200)  
       students = models.ManyToManyField(  
           "Student",   
           related_name="enrolled_courses"  
       )  

   #referenced here using  

   student = Student.objects.first()  
   student.enrolled_courses.all()  # instead of student.course_set.all()  
Enter fullscreen mode Exit fullscreen mode
  1. blank and null: Blank and Null are boolean parameters; null=True means the database can store NULL values, while blank=True means validation allows empty values.
   class Profile(models.Model):  
       bio = models.TextField(blank=True, null=True)  

Enter fullscreen mode Exit fullscreen mode
  1. Through: This is unique for the many-to-many field, it lets you define a custom intermediate model for many-to-many relationships.
   class Enrollment(models.Model):  
       student = models.ForeignKey("Student", on_delete=models.CASCADE)  
       course = models.ForeignKey("Course", on_delete=models.CASCADE)  
       enrolled_at = models.DateTimeField(auto_now_add=True)  
       grade = models.CharField(max_length=2, blank=True)  

   class Course(models.Model):  
       title = models.CharField(max_length=200)  
       students = models.ManyToManyField("Student", through="Enrollment")  

   # usage below  
   student = Student.objects.first()  
   course = Course.objects.first()  
   Enrollment.objects.create(student=student, course=course, grade="A")  
Enter fullscreen mode Exit fullscreen mode

From this article, we’ve been able to break down relationships in Django, their parameters, and how they’re referenced. Next, we’ll move into understanding Django managers.

Top comments (0)