Dushyant Deshwal
Dushyant Deshwal

Reputation: 419

Best approach to use Many to Many in Django + SQL

I am making a web app and i wish to use many to many fields in models.I haven't given much thought before and have simply used many to many field in models but now i am thinking how actually these many to many are stored in database and what would be the best approach when using Many to Many Fields in Models.

Approach 1:

class Company(models.Model):
    name = models.CharField(max_length = 190,blank = False,null = False)
    about = models.CharField(max_length = 260,blank = False,null = True)
    website = models.URLField(blank = False)
    address  = models.OneToOneField(Address,related_name="org_address",on_delete=models.SET_NULL,null=True)
    admin = models.ManyToManyField(User,related_name="org_admin",blank = False)
    created_on = models.DateTimeField(default = timezone.now)
    updated_on = models.DateTimeField(default = timezone.now)

OR Approach 2:

class Company(models.Model):
    name = models.CharField(max_length = 190,blank = False,null = False)
    about = models.CharField(max_length = 260,blank = False,null = True)
    website = models.URLField(blank = False)
    address  = models.OneToOneField(Address,related_name="org_address",on_delete=models.SET_NULL,null=True)
    created_on = models.DateTimeField(default = timezone.now)
    updated_on = models.DateTimeField(default = timezone.now)

class CompanyAdmin(models.Model):
    admin = models.ManyToManyField(User,related_name="org_admin",blank = False)
    company = models.ForeignKey(Company,related_name="company",on_delete=models.CASCADE)

Do both methods handle many to many fields in the same way ?

I am using MySQL as Database

Update "To make them Equivalent, Second Approach should have field as ForiegnKey and not many to many" also to avoid multiple company admin entries Field company should be one to one.

Solution

Do not create join tables as Django ORM Handles this itself.

Upvotes: 2

Views: 646

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477814

but now I am thinking how actually these many to many are stored in database.

Django will construct a model that has two ForeignKeys, one to the Company and one to the User model. This model thus corresponds to the junction table [wiki] between the Company and User model.

A ManyToManyField thus does not map on a column. The ManyToManyField is more a concept that enables one to write simpler queries, and provides a more convenient interface.

Do both methods handle many to many fields in the same way ?

No. With the latter you will make two extra tables, one for the CompanyAdmin model, and one for the ManyToManyField between CompanyAdmin and User. It would also result in more JOINs to fetch the companies for which a User is an admin for example, and it would here be possible to construct multiple CompanyAdmins for the same Company, and thus linking the same User multiple times.

You can define however custom attributes in the junction table, by specifying the junction model explicitly with the through=… parameter [Django-doc]:

from django.conf import settings

class Company(models.Model):
    admin = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='org_admin',
        through='CompanyAdmin'
    )
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)

class CompanyAdmin(models.Model):
    admin = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    company = models.ForeignKey(
        Company,
        on_delete=models.CASCADE
    )

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Note: Django's DateTimeField [Django-doc] has a auto_now_add=… parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False), such that it does not appear in ModelForms by default.

Upvotes: 1

Related Questions