Django Models – ForeignKey (OneToMany Relationship)
To make a One-To-Many relationship, Django uses ForeignKey
. There are two key arguments you need to specify.
- Related model name
- On_delete argument
As explained on the previous page, by specifying a related model name through the ForeignKey
field, Django connects the field with the ID of the related model. The on_delete
argument is used to define the behavior when an object of the related model is deleted.
There are three possible values for the on_delete
argument.
CASCASE
: deletes the object containing theForeignKey
.PROTECT
: prevents deletion of the referenced object by raisingProtectedError
RESTRICT
: prevents deletion of the referenced object by raisingRestrictedError
As the possible values are available in django.db.models
, you need to write on_delete=models.CASCADE
.
Practice
Objective:
Learn how to use ForeignKey
In this practice, we'll explain how to use ForeignKey
to create One-To-Many Relationship. In this case example, we'll add a division
field in the Employee model by connecting it with the Division model.
1. Add a new field in the Employee model in models.py
Edit the Employee model in the models.py file to connect with the Division model.
- Field name:
division
- Field type:
ForeignKey
- Related model name:
Division
- On_delete:
models.CASCADE
The yellow line below is the new code.
from django.db import models
import datetime
class Employee(models.Model):
PRIORITIES=[('H','High'), ('M','Medium'), ('L','Low'),]
name=models.CharField(max_length=25, verbose_name="Employee Name")
priority=models.CharField(max_length=1, choices=PRIORITIES, default="M", verbose_name="Learning Priorities")
reg_date=models.DateField(default=datetime.date.today, verbose_name="Data Registration Date")
division=models.ForeignKey(Division, on_delete=models.CASCADE)
def __str__(self):
return self.name
2. Move the Division model before the Employee model in models.py
Cut the code of the Division model and paste the code before the Employee model in the models.py file. This is needed because the Employee model will refer to the Division model in the new field.
from django.db import models
import datetime
class Division(models.Model):
:
def __str__(self):
return self.div_name
class Employee(models.Model):
:
3. Run the makemigrations command
Run the makemigrations
command.
python manage.py makemigrations employee_learning
As there are existing records, you'll encounter the message below.
It is impossible to add a non-nullable field 'division' to employee without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit and manually define a default value in models.py.
Select an option:
Answer 1
at this time. Then, the prompt is asking what data should be filled in.
Select an option: 1
Please enter the default value as valid Python.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
>>>
Here, you need to be careful. You should not input the data that is not available. As we need to input an available ID created in the Division model, type "1
" for now.
>>> 1
Migrations for 'employee_learning':
employee_learning/migrations/0007_employee_division.py
- Add field division to employee
4. Migrate the model into the database and run the runserver
Complete the migration
and run the runsever
command.
python manage.py migrate
python manage.py runserver
5. Check the Django admin site
You can see that the Division model and the Employee model are connected. The employee model also reflects the data as we temporality input "1
" for existing data. ID:1 is "Product Development" in this case.