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
- 1 Article can
- Artist m2m rel with Movies
- 1 Artist can be in many Movie
- 1 Movie can
have
many Artist
- Collection – Product
- Cart – Product
- Product m2m rel with Collection
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')
related_name
- The related_name attribute specifies the name of the
reverse relation
from the User model back to your model - If you don’t specify a related_name, Django automatically creates one using the name of your model with the suffix
_set
. - https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html
- Modify A
- publications = models.ManyToManyField(Publication, related_name=‘article_pub’)
- Now
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
related_query_name
- It allows you to
filter on the reverse relationship
of a foreign key related field. - https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html
- Modify A
- publications = models.ManyToManyField(Publication, related_name=‘article_pub’,related_query_name=‘arti’)
- if related_query_name is used
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