Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use "through" argument for ManyToManyField in Django models?

Looking through the Django docs and trying to figure out the use of the "through" argument. Here is a link to the doc.

The example:

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)

Why is the "members" attribute of Group even needed? Isn't the 'group' ForeignKey of Membership enough to follow the relation and access that information?

like image 879
Matt Parrilla Avatar asked Jan 11 '12 17:01

Matt Parrilla


People also ask

What is through in Django models?

The through attribute/field is the way you customize the intermediary table, the one that Django creates itself, that one is what the through field is changing.

What is ManyToManyField Django?

ManyToManyRel is used by the ManyToManyField to implement the relationship object for the Field base class which it extends.

How fetch data from many to many field in Django?

A ManyToManyField in Django is a field that allows multiple objects to be stored. This is useful and applicable for things such as shopping carts, where a user can buy multiple products. To add an item to a ManyToManyField, we can use the add() function.


2 Answers

I think you're thinking a little too literally about this. Let's say you didn't use through:

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)

    def __unicode__(self):
        return self.name

Django, behind the scenes, essentially creates the following model for you:

class GroupPerson(models.Model)
    group = models.ForeignKey(Group)
    person = models.ForeignKey(Person)

The reason for creating a Membership model is to add extra data that the default model Django automatically creates wouldn't have by default, but since you're no longer using the default, you have to tell Django that, using through. Basically, you're preserving the API Django provides for ManyToManyFields.

like image 151
Chris Pratt Avatar answered Oct 21 '22 11:10

Chris Pratt


The reason why one would do this is so that Group has a field for this relationship, rather than having to follow the relationship back through its membership_set.

If nothing else, this can make writing queries simpler. At the very least, this can make a programmer's life easier, and code easier to read. A sufficiently optimising ORM would be able to generate appropriate indices to speed up such access (and unless I'm very much mistaken, django does indeed do that; or at least South does).

like image 29
Marcin Avatar answered Oct 21 '22 09:10

Marcin