Django Models Part 2 (Models Relationship)

Search for a command to run...

Let's implement (1-M) relation on Django (ForeignKey)
from django.db import models
class Address(models.Model):
.....
.....
.....
class User(models.Model):
.....
.....
.....
address = models.OneToOneField(Address, on_delete=models.CASCADE)
I think you need to change that line address To be ForeignKey instead of OneToOne
This series will cover the core concepts on web application development using Django, from basic installation to user authentications and some core concepts. Status: 9/14 published ✅
Model Manager A Manager is the interface through which we perform ORMs in Django models By Default, Django automatically adds a Manager with a name of objects. This is the reason we are able to use objects and query to our Models eg: Model.objects.a...
Nothing serious, just experimenting on Django Framework

Working with simple media uploads and serving these media files

Using static files like JavaScript, CSS, images with Django

Class() based views in Django

function() based views in Django

Table A can have only one matching row in Table BLet's take an example of simple 1-1 relationship between user and user_detail table

Here, in this figure we can see that, a row from user table (Table A) can only reference a row (1 row) for user_detail (Table B) through user_detail_id
column on user table (Table A)
user_detail table (table B) could have been stored on user table (Table A) and we could have just ignored the relationship, but this relationship is quite useful when you have lot's of column in your table and you want to separate those columns in different table according to their business natureOneToOneField)# models.py
from django.db import models
class UserDetail(models.Model):
address = models.CharField(max_length=100)
phone_number = models.CharField(max_length=20)
date_of_birth = models.DateField()
github_username = models.CharField(max_length=50)
class User(models.Model):
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50)
email = models.EmailField()
# note: do not save password in plain text
password = models.CharField(max_length=50)
user_detail = models.OneToOneField(UserDetail,
on_delete=models.CASCADE)
so using models.OneToOneField we can easily create up 1-1 relation between different models in Django.
You could have switched the relationship as well, i.e 1-1 relation from UserDetail to User
Basic ORM to create data/rows for this relation
# import your model
# i.e from app.models import UserDetail, User
detail = UserDetail.objects.create(
address="Lake Street",
phone_number='123456',
date_of_birth='2000-01-01',
github_username='django'
)
user = User.objects.create(
first_name='Django',
last_name='Django',
email="django@example.com",
password="django",
user_detail=detail # reference to the user_detail instance created above
)
Table A can have matching row in Table B but a row in Table B can only have one matching row in Table Aaddress and user table
address (Table A) can be referenced by many rows from user (Table B). i.e a user can have only one address but a address can be of multiple users1 Address = Multiple Users but 1 User = 1 Address1 User= Multiple Address and 1 Address = 1 User, in such a case, we can reverse this relation and call it Multiple Address = 1 User and call this relation a Reverse One to Many Relation as shown in the figure below
Now, there lies a big confusion on the 1-M and Reverse 1-M, because both looks same. Infact, both of them looks same, but the only difference occurs when you look the relationship from table point of view. i.e In the reverse 1-M figure, we named it Reverse relation because we looked the relation from
addresspoint of view, but if you had looked the relation fromuserpoint of view, then it would have been a normal 1-M relationHow you prepare your 1-M relation matters when you try to perform db query for the data
ForeignKey)from django.db import models
class Address(models.Model):
name = models.CharField(max_length=100)
latitude = models.CharField(max_length=100)
longitude = models.CharField(max_length=100)
class User(models.Model):
email = models.EmailField()
name = models.CharField(max_length=50)
password = models.CharField(max_length=50)
address = models.ForeignKey(Address, on_delete=models.CASCADE)
Basic ORM to create rows for this relation
address = Address.objects.create(
name="Lake Street",
latitude='1.1',
longitude='2.2',
)
# or to get already created object
# address = Address.objects.get(name='Lake Street')
user = User.objects.create(
name='Django',
email="django@example.com",
password="django",
address=address # reference to the address instance from above
)
Table A can have many matching rows in Table B and vice versa1-M relation. i.e 1-M and M-1user and address table
user and address is maintained by an intermediate table Table C, this way we can achieve a relation where a user can have multiple address and a address can have multiple userManyToManyField)from django.db import models
class Address(models.Model):
name = models.CharField(max_length=100)
latitude = models.CharField(max_length=100)
longitude = models.CharField(max_length=100)
class User(models.Model):
email = models.EmailField()
name = models.CharField(max_length=50)
password = models.CharField(max_length=50)
address = models.ManyToManyField(Address)
This looks so simple, isn't it? But i can feel a big confusion. We discussed that a M-M relation would need an intermediate table but on the Django end we just created two models without an intermediate one, This is due to the awesome implementation of Django where, Django automatically creates an intermediate table when we define our field with
models.ManyToManyField, but don't worry you can always tellmodels.ManyToManyFieldto point to some custom intermediate table or you can even implementM-Mwith just1-MandM-1relation without even usingmodels.ManyToManyField
Basic ORM to create rows for this relation
address = Address.objects.create(
name="Lake Street",
latitude='1.1',
longitude='2.2',
)
# or to get already created object
# address = Address.objects.get(name='Lake Street')
# first create user object
user = User.objects.create(
name='Django',
email="django@example.com",
password="django",
)
# add address to user/user to address
user.address.add(address)
# to remove address from user/user from address
user.address.remove(address)
models.ManyToManyFieldBy using just 1-M relation and an intermediate table let's try to create M-M relations
from django.db import models
class Address(models.Model):
name = models.CharField(max_length=100)
latitude = models.CharField(max_length=100)
longitude = models.CharField(max_length=100)
class User(models.Model):
email = models.EmailField()
name = models.CharField(max_length=50)
password = models.CharField(max_length=50)
# intermediate table
class UserAddress(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
address = models.ForeignKey(Address, on_delete=models.CASCADE)
Basic ORM for this custom way
address = Address.objects.create(
name="Lake Street",
latitude='1.1',
longitude='2.2',
)
user = User.objects.create(
name='Django',
email="django@example.com",
password="django",
)
user_address = UserAddress.objects.create(
user=user,
address=address,
)
on_delete
As you can see we used on_delete argument on our OneToOneField and ForeignKey field, but what does it do?
ForeignKey and want to delete the row when the object referenced by foreign key gets deleted from django.db import models
class Info(models.Model):
name=models.CharField(max_length=20)
user= models.ForeignKey(User, on_delete=models.CASCASE)
Here, The Info objects/rows gets deleted when the referenced user gets deleted on the User table
on_deletemodels.CASCADEmodels.PROTECTmodels.SET_NULL
and more...related_name
related_name attribute specifies the name of the reverse relationrelated_name Django automatically created related_name for every FK automatically, whose default value is:ForeignKeyOneToOneField