djangodjango-models

Understanding ManyToMany fields in Django with a through model


I'm having trouble understanding the use of ManyToMany models fields with a through model. I can easily achieve the same without the ManyToMany field. Considering the following from Django's docs:

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


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


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

What I don't understand, is how is using the ManyToMany field better than simply dropping it and using the related manager. For instance, the two models will change to the following:

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


class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name='members')
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

What am I missing here?


Solution

  • You're right, if you define the membership table explicitly then you don't need to use a ManyToManyField.

    The only real advantage to having it is if you'd find the related manager convenient. That is, this:

    group.members.all()  # Persons in the group
    

    looks nicer than this:

    Person.objects.filter(membership_set__group=group)  # Persons in the group
    

    In practice, I think the main reason for having both is that often people start with a plain ManyToManyField; realize they need some additional data and add the table explicitly; and then continue to use the existing manager because it's convenient.