Django Relationships

Posted by Daksh on Saturday, August 6, 2022

Relationships between models

Often, the data in your application will be related in some way. Therefore, you will need to define relationships between your models. Django supports all the common database relationships: many-to-one, many-to-many and one-to-one.

Implementing a one to many relationship between 2 models

A ForeignKey field is used to define a many-to-one relationship.

from django.db import models

class Entity1(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

 
class Entity2(models.Model):
    field1 = models.CharField(max_length=100)
    field2 = models.TextField()
    # Now, we can define a relationship between Entity1 and Entity2 using a ForeignKey field.
    # ForeignKey is a field that points to another model.
    # It takes a positional argument that is the model to which the model is related to.
    # It also has a on_delete argument that specifies what happens to the related object when the object it is related to is deleted.
    # options are CASCADE, PROTECT, SET_NULL, SET_DEFAULT, SET(), DO_NOTHING
    entity1 = models.ForeignKey(Entity1, on_delete=models.CASCADE)

Entering data with shell

>>> from myapp.models import Entity1, Entity2
# it is important to create the Entity1 object first, because Entity2 has a ForeignKey to Entity1
>>> e1 = Entity1(name='any_name', description='This is entity1')
>>> e1.save()
# point to the Entity1 object using the entity1 attribute
>>> e2 = Entity2(field1='Anything', field2='Anything2', entity1=e1)
>>> e2.save()
# to print the name of the Entity1 object that is related to Entity2, use the entity1 attribute
>>> e2.entity1.name
# the e1 object is not saved in the Entity2 table, but it is saved in the Entity1 table

CrossModel queries

Finding all the Entity2 objects that have same name.

# filtering Entity2 on the basis of field2
>>> Entity2.objects.filter(field2='Anything2')
# filtering Entity2 on the basis of Entity1 name
>>> Entity2.objects.filter(entity1__name='any_name')
# filtering Entity2 on the basis of Entity1 name with contains filter
>>> Entity2.objects.filter(entity1__name__contains='any')
# Django will create a "entity2_set" attribute on the Entity1 object
# this attribute will be a QuerySet of all the Entity2 objects that are related to the Entity1 object
# in short, inverse relationship
>>> obj = Entity1.objects.get(name='any_name')
>>> obj.entity2_set.all()
# inside ForeignKey, we can also use related_name argument
# this will be the name of the attribute that will be created on the Entity1 object
# supopose inside ForeignKey, we use "related_name='entity2_items'"
>>> obj.entity2_items.all()

Implementing a one to one relationship between 2 models

Add relationship field to the Entity that makes more sense, although you can add to any of them. For example, if you have a ‘Person’ model and an ‘Address’ model, you might want to add the relationship to the ‘Person’ model. It is implemented using OneToOneField.

from django.db import models

class Entity1(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

class Entity2(models.Model):
    field1 = models.CharField(max_length=100)
    field2 = models.TextField()
    entity1 = models.OneToOneField(Entity1, on_delete=models.CASCADE)

For one-to-one relationships, you don’t need to specify a related_name attribute, because there is only one related object and Django will automatically create a reverse relationship with the same name as the model with the lowercase first letter.

Difference between OneToOneField and OneToOneRel is that OneToOneField is used to define a one-to-one relationship between two models, whereas OneToOneRel is used to define a reverse relationship between two models.

Implementing a many to many relationship between 2 models

It is implemented using ManyToManyField.

from django.db import models

class Entity1(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

class Entity2(models.Model):
    field1 = models.CharField(max_length=100)
    field2 = models.TextField()
    # ManyToMany does not have on_delete argument
    # Django creates a new mapping table to store the relationship between Entity1 and Entity2
    entity1 = models.ManyToManyField(Entity1)

While querying, avoid using assignment operator, because each object will have list of values, and therefore use add() and remove() methods. These methods only work on ManyToMany relationships.

>>> e1 = Entity1.objects.get(name__contains='any')
>>> e2 = Entity2.objects.get(field1='Anything')
# add() method adds the Entity1 object to the Entity2 object
# do not use e2.entity1 = e1
>>> e2.entity1.add(e1)
# remove() method removes the Entity1 object from the Entity2 object
>>> e2.entity1.remove(e1)
# clear() method removes all the Entity1 objects from the Entity2 object
>>> e2.entity1.clear()

Primary key

Primary key is a unique identifier for each instance. It cannot be null and it must be unique. It can be an integer or CharField or TextField.