12

An example Many-to-Many through relationship in Django:

class First(models.Model):
    seconds = models.ManyToManyField(Second, through='Middle')

class Middle(models.Model):
    first = models.ForeignKey(First)
    second = models.ForeignKey(Second)

class Second(models.Model):

Following the documentation on intermediary models, only one model of the pair to be related contains the ManytoManyField, model First in the example above. Is this correct?

If so, which model should contain the ManytoManyField field? Are there any differences in using the relationship from either end depending on where the ManytoManyField is?

Thanks

EDIT (I should have been clearer):

I'm interested in an Intermediary table because I will have additional data to store on the relationship.

When I say usage, I don't mean defining the models, I mean using the relationship (otherwise I'd let Django do it's thing).

If I want all Seconds related to a First, would it be exactly the same as getting all Firsts related to a Second, or would the ManytoManyField make one direction easier to do than the other by introducing any extra functionality?

StringsOnFire
  • 2,726
  • 5
  • 28
  • 50

2 Answers2

22

There shouldn't be a difference from an operational perspective, so the only difference would be in the definition of the model and things that affect it (for instance, Manager classes).

You also don't always need to define a "through" class. Django does that automatically for you, and all that class really does is maintain a third table to track the respective IDs for each related record in the two other tables. You have to decide whether you want to add anything to that third table that is important.

For instance, say you are designing a web app for a conference. They might want to store information about the attendees (both individuals and companies), as well as the speakers and sponsors (also individuals and companies). Part of your models for companies might look like this:

class Company(models.Model):
    name = models.CharField(max_length=100)
    sponsored_segment = models.ForeignKey(ConferenceSegment, null=True)

class ConferenceSegment(models.Model):
    title = models.CharField(max_length=100)

But that gets cumbersome quickly, and you'll have lots of attending companies that have nothing to do with sponsoring. Also, you might want to track their rank/package on the website (after all, bigger sponsors get bigger placement):

class Company(models.Model):
    name = models.CharField(max_length=100)

class ConferenceSegment(models.Model):
    title = models.CharField(max_length=100)
    sponsors = models.ManyToManyField(Company, through=u'Sponsor', related_name=u'sponsored_segments')

class Sponsor(models.Model):
    company = models.ForeignKey(Company)
    segment = models.ForeignKey(ConferenceSegment)
    rank = models.PositiveIntegerField()

Notice also the "related_name" attribute in the ManyToManyField. This means that we can access the ConferenceSegment object via a Company instance by using that name:

c = Company.objects.get(...)
segments = c.sponsored_segments.all()

Hope this helps.

JoeLinux
  • 4,198
  • 1
  • 29
  • 31
  • What would you do without that related_name? Seems like that's a benefit of declaring the ManytoManyField in one model over the other? Would `segments = c.segments.all()` work? What about the other way, `s = Segment.objects.get(...) companies = s.companies.all()` ? – StringsOnFire Jul 27 '15 at 15:36
  • 1) It would use Django's default naming. So in the example case above, it would be `conferencesegment_set` instead of `sponsored_segments`. The `related_name` helps you make the name more appropriate for the relationship. 2) Sure, if you want to save typing. 3) Yes, if `segments` was the `related_name`. 4) The correct query would be `s.sponsors.all()`. – JoeLinux Jul 27 '15 at 15:48
  • Got it, so there's no functional difference based on where the `ManyToManyField` goes, the only advantage is use of related_name as opposed to the Django default. – StringsOnFire Jul 27 '15 at 15:57
  • How do we insert multiple records into this ManyToMany field with single query? – Vijay Nov 19 '22 at 19:54
3

When you add a many to many field to a model a separate table is created in the database that stores the links between two models. If you don't need to store any extra information in this third table then you don't have to define a model for it.

class First(models.Model):
    seconds = models.ManyToManyField(Second, related_name='firsts')

class Second(models.Model):
    pass

I can't think of any difference between defining the many to many field in the First or Second models:

class First(models.Model):
    pass

class Second(models.Model):
    firsts = models.ManyToManyField(First, related_name='seconds')

In both cases usage is the same:

firsts = my_second.firsts
seconds = my_first.seconds
nima
  • 6,566
  • 4
  • 45
  • 57