94

I want to store some additional information in that, automatically created, ManyToMany join-table. How would I do that in Django?

In my case I have two tables: "Employees" and "Projects". What I want to store is how much each of the employees receives per hour of work in each of the projects, since those values are not the same. So, how would I do that?

What occurred to me was to, instead of the method "ManyToManyField", create explicitly a third class/table to store those new informations and to set its relationship with "Employees" and "Projects" using the "ForeignKey" method. I'm pretty sure it will work, but is this the best approach?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
rrb_bbr
  • 2,966
  • 4
  • 24
  • 26
  • 3
    Possible duplicate of [How to add column in ManyToMany Table (Django)](http://stackoverflow.com/questions/12567151/how-to-add-column-in-manytomany-table-django) – ravi404 Oct 22 '15 at 06:23
  • @ravz Why shouldn't that one be closed as a dupe of this one, instead? – TylerH Oct 22 '15 at 18:50
  • @TylerH this is an older post. However both the questions have answers , i'd suggest merging these. – ravi404 Oct 26 '15 at 08:45

1 Answers1

136

Here is example of what you want to achieve:

http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

In case link ever breaks:

from django.db import models

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

    def __str__(self):              # __unicode__ on Python 2
        return self.name

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

    def __str__(self):              # __unicode__ on Python 2
        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)
gruszczy
  • 40,948
  • 31
  • 128
  • 181
  • 4
    How can I access the date_joined in a template?Group.date_joined does not work. – Timo Aug 31 '14 at 13:18
  • Group date joined won't work, because Group itself doesn't join anything. Instead, you can get it's members and get their join time. for member in group.members.all(): – gruszczy Sep 01 '14 at 04:48
  • 2
    How can I use group.members.add() with the above approach? – Dejell Mar 05 '17 at 08:07
  • @Dejell the code samples in the link mentioned might help you. – Devesh Khandelwal Apr 06 '17 at 09:56
  • 2
    You can access the glue model object with _set. So group.membership_set.all() for example. Note you always lowercase the entire model name to find this attribute and then add _set. – Sensei Mar 14 '18 at 02:38
  • through='Membership' , it is not creating the table in database. kindly help me. – Kabali Feb 07 '20 at 13:28
  • Existing ManyToMany fields cannot be altered by adding or removing 'through=', according to the migration exception I just ran into. – Tristan Brown Feb 23 '21 at 01:18
  • To get around the "M2M fields cannot be altered" exception: https://stackoverflow.com/questions/26927705/django-migration-error-you-cannot-alter-to-or-from-m2m-fields-or-add-or-remove – Tristan Brown Feb 23 '21 at 01:26