Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use a seperate table instead of many to many field in Django

I needed to assign one or more categories to a list of submissions, I initially used a table with two foreign keys to accomplish this until I realized Django has a many-to-many field, however following the documentation I haven't been able to duplicate what I did with original table.

My question is : Is there a benefit to using many-to-many field instead of manually creating a relationship table? If better, are there any example on submitting and retrieving many-to-many fields with Django?

like image 884
afshin Avatar asked Jul 12 '11 01:07

afshin


1 Answers

From the Django docs on Many-to-Many relationships:

When you're only dealing with simple many-to-many relationships such as mixing and matching pizzas and toppings, a standard ManyToManyField is all you need. However, sometimes you may need to associate data with the relationship between two models.

In short: If you have a simple relationship a Many-To_Many field is better (creates and manages the extra table for you). If you need multiple extra details then create your own model with foreign keys. So it really depends on the situation.

Update :- Examples as requested:

From the docs:

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

You can see through this example that membership details (date_joined and invite_reason) are kept in addition to the many-to-many relationship.

However on a simplified example from the docs:

class Topping(models.Model):
    ingredient = models.CharField(max_length=128)

class Pizza(models.Model):
    name = models.CharField(max_length=128)
    toppings = models.ManyToManyField(Topping)

There seems no need for any extra data and hence no extra model.

Update 2 :-

An example of how to remove the relationship.

In the first example i gave you have this extra model Membership you just delete the relationship and its details like a normal model.

for membership in Membership.objects.filter(person__pk=1)
    membership.delete()

Viola! easy as pie.

For the second example you need to use .remove() (or .clear() to remove all):

apple = Toppings.objects.get(pk=4)
super_pizza = Pizza.objects.get(pk=12)

super_pizza.toppings.remove(apple)
super_pizza.save()

And that one is done too!

like image 160
James Khoury Avatar answered Nov 15 '22 07:11

James Khoury