Relationship

Django supports relational databases and allows us to establish relations between different models. There are three types of relational fields which Django supports: many-to-one, many-to-many and one-to-one.

class Person(models.Model):
    name = models.CharField(max_length=255)  # Mandatory

# O2O
class Aadhar(models.Model):
    person = models.OneToOneField("Person",on_delete=models.CASCADE)
    aadhar_no = models.TextField(max_length=100)

# M2O(FK)
class Posts(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Person, on_delete=models.CASCADE)


class Publication(models.Model):
    title = models.CharField(max_length=30)

## M2M
class Article(models.Model):
    headline = models.CharField('Article Name',max_length=100)
    publications = models.ManyToManyField(Publication)

O2O

This is used when one record of a model A is related to exactly one record of another model B.

  • models.OneToOneField(on_delete=REQUIRED)
  • Eg:
    • Child rel with Parent
    • Profile rel with Users
    • Aadhar(sign,a_no) Rel with Person/User
    • CustomerOrder rel with CustomerOrderAddress
Person.object.first().adhar

Adhar.object.first().person

M2O

This is used when one record of a model A is related to multiple records of another model B.

  • models.ForeignKey(Person, on_delete=REQUIRED)
  • Eg:
    • Child rel with Parent
    • Posts rel with Users –> Many post is linked to 1 user
    • Car rel with Manufacturer –> Many car is linked to 1 Manufacturer
    • Order, Address rel with User
Person.objects.first().posts_set.all()

Posts.objects.first().person

M2M

This is used when one record of a model A is related to multiple records of another model B and vice versa.

  • The M2M relation is stored in db by creating a new table collection_product.
  • This table is consist of id, collection_id, product_id
class Product(models.Model):
	name = models.CharField(max_length=50)

class Collection(models.Model):
    name = models.CharField(max_length=50)
    collection_products = models.ManyToManyField(Product)

Alt Way to define M2M - using through

  • By using through we can override the default relation table.
  • Can have our own-naming, additional common fields.
from product.models import Product
from custcollections.models import Collection, CollectionProduct

class Product(models.Model):
	name = models.CharField(max_length=50)

class Collection(models.Model):
    name = models.CharField(max_length=50)
	collection_products = models.ManyToManyField(
			Product, through='CollectionProduct')

class CollectionProduct(models.Model):
    collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
  • models.ManyToManyField(on_delete=NOT REQUIRED)
  • Eg:
    • Product m2m rel with Collection
      • 1 Prod can be in many Coll
      • 1 Coll can have many Prod
    • Article m2m rel with Publications
      • 1 Article can have many Pub
      • 1 Pub can have many Article
    • Artist m2m rel with Movies
      • 1 Artist can be in many Movie
      • 1 Movie can have many Artist
    • Collection – Product
    • Cart – Product
  • NOTE:
    • Rel can be defined where we use have.

Find all Prods in a Coll

Collection.objects.get(id=4).collection_products.all()
Product.objects.filter(collection__id=4)
# <QuerySet [<Product: Product object (26)>]>

Find all Colls that have certain Prod

Product.objects.get(id=26).collection_set.all()
Collection.objects.filter(collection_products__id=26)
# <QuerySet [<Collection: Collection object (4)>, 
# <Collection: Collection object (296)>]>

Add/Remove prod from coll

coll = Collection.objects.create(name='collection1')
p1 = Product.objects.get(id=1)
p2 = Product.objects.get(id=2)

# Add
col.collection_products.add(p1, p2)
# Remove
col.collection_products.remove(p1)
  • Also update the through rel table
col.collection_products.add(p1, through_defaults={'is_active': False})
class Publication(models.Model):
    title = models.CharField(max_length=30)

## M2M
class Article(models.Model):
    headline = models.CharField('Article Name',max_length=100)
    publications = models.ManyToManyField(Publication,
    		related_name='article_pub',related_query_name='arti')
Publication.objects.get(pk=1).article_set.all() # Fails
Publication.objects.get(pk=1).article_pub.all() # Works

Publication.objects.filter(article__pk=1) #  Fails
Publication.objects.filter(article_pub__pk=1) # Works
Publication.objects.filter(article__pk=1) 	# Fails
Publication.objects.filter(article_pub__pk=1) 	# Fails
Publication.objects.filter(arti__pk=1) 	# Works

Publication.objects.get(pk=1).article_set.all() 	# Fails 
Publication.objects.get(pk=1).article_pub.all() 	# Works
Publication.objects.get(pk=1).arti.all() 	# Fails