Skip to main content

Understanding and Implementing One To One, One to Many and Many to Many relationships in Django

In this post we will discuss the basics of model mappings in Django for One to One, One to Many and Many to Many relationships. Before we proceed, lets try to quickly refresh basic relational database concepts.

Relational Database Table : 
A relational database consists of one or more table(s) with each table having rows and columns. Think of table as a grid with column(s) going from left to right and the rows representing the data. Columns are defined to hold a specific type of data, for example, dates, numeric, strings etc. A table can contain zero or more rows while if the rows are zero, table is said to be empty. Example would be  a table of employees in a company.

Primary Key : 
A Primary Key is the combination of one or more columns, whose data is used to uniquely identify the rows in the table. It acts like an address used to identify the homes for postal delivery. If there are more columns are used to represent the primary key, then the combination of data in these columns is used to uniquely represent the rows in table. Example would be "Employee ID" in a table of employees. 

Foreign Key : 
A Foreign Key is the combination of one or more columns that refer to the Primary Key of an another table. Example would be a second table dealing with Employee Details which will have the "Employee ID" as a Foreign Key (This is acting as a Primary Key in Employees table).

One to One Relationship :
One to One relationship means that each row in a database table is linked with one and ONLY one other row in another table. So, if we have two tables A and B, then each row in A is linked with other row in B.

Lets take an example to understand it better :- 
           Consider a case where we have two database tables holding the records of Persons and the Passports. Now, in any country, one person can hold only one passport for that country. If we have to represent this in database, we have to identify the Parent and Child table. In our example, Persons table would be the primary table since a person can exist even without a passport. To represent the One to One relationship in a database, the child table must hold the Foreign Key which actually serves as the Primary Key for that table. So, in this way, you can't hold the duplicate records for the Parent table in Child table. As you can see that the Child table is not having its own primary key and rather is using the Foreign Key as its own Primary Key. So, it is clear that the Foreign Key must be unique in this case.

from django.db import models
class Persons(models.Model):
    person_id = models.IntField()
    name = models.CharField(max_length=50)
    def __str__(self):
        return "%s is the person name" % self.name

class Passports(models.Model):
    person_id = models.OneToOneField(
        Persons,
        on_delete = models.CASCADE,
        primary_key = True,
    )
    passport_number = models.IntField()
    def __str__(self):
        return "%s is the person name" % self.person_id.name
Internally OneToOneField in Django is actually a ForeignKey with Unique=True

One to Many Relationship :
In One to Many Relationship, we can have an one table whose rows can be referenced by multiple rows in an another table.

             An example would be the "Employer" and "Employees" table where we can have multiple employees belonging to a unique employer. In this case also, we need to identify Parent and Child tables. As a general rule, the table with One attribute is the Primary table and the other table as Child table. In terms of database, the Child table must hold the Foreign Key and should have an additional Primary Key unlike One to One mapping where the Foreign Key acts as a Primary Key.

In Django, we do not have One to Many Relationship field as such and ForeignKey field should be used to achieve this.
from django.db import models
class Employer(models.Model):
    employer_id = models.IntField(primary_key=True)
    employer_name = models.CharField(max_length=50)
    def __str__(self):
        return "%s is the employer name" % self.employer_name

class Employees(models.Model):
    employee_id = models.IntField(primary_key=True)
    employer_id = models.ForeignKey(Employer,on_delete=models.CASCADE)
    employee_name = models.CharField(max_length=50)
    def __str__(self):
        return "%s is the employer name" % self.employer_id.employer_name


Many to Many Relationship :
In Many to Many Relationship, the rows from both the tables can reference each other with no limits. Typically, in database, this is handled by a "join table" which will be the third table having the primary keys of both the tables.

             An example would be the "Student" and "Course" tables. In this case, it would be tricky to establish Parent Child relationship. One way is to try to identify which table can exist without the other. In our case, clearly it is Student which should be the Primary table.


from django.db import models
class Student(models.Model):
    student_name = models.CharField(max_length=50)
    def __str__(self):
        return self.student_name

class Course(models.Model):
    course_name = models.CharField(max_length=50)
    students = models.ManyToManyField(Student)
    def __str__(self):
        return self.course_name

Internally Django creates a new table which has two Foreign Keys - Primary Key from Student table and Primary Key from Course table. It also creates one unique composite key comprising both the foreign keys.

Comments