10

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?

Marcin
  • 48,559
  • 18
  • 128
  • 201
Matt Parrilla
  • 3,171
  • 6
  • 35
  • 54

4 Answers4

15

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.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
3

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).

Marcin
  • 48,559
  • 18
  • 128
  • 201
2

It's so that, from Group, you can directly access the members. You don't necessarily want to deal with Membership objects directly (the user my never even see them). You just want groups with some extra information stored. Think of Membership as meta-data on the association between Person and Group.

jeffknupp
  • 5,966
  • 3
  • 28
  • 29
  • But what would the difference be between having members stored as a ManyToMany in Groups rather than needing to follow a backwards relation to Membership? – Matt Parrilla Jan 11 '12 at 17:20
  • I guess my real question is, why don't I want to deal with Membership objects directly? – Matt Parrilla Jan 11 '12 at 17:22
  • 1
    Because you would typically be dealing with a Person object or a Group object as the result of some action by the user. A Membership object is most likely just some data that you would occasionally display, but would not be something you would be passing around between the view/template. – jeffknupp Jan 11 '12 at 17:33
1

through tables are used to store properties of the relation, in this case, e.g. the date a Person joined a particular Group

second
  • 28,029
  • 7
  • 75
  • 76