Skip to content

Instantly share code, notes, and snippets.

@jacobian
Created February 15, 2011 18:11
Show Gist options
  • Save jacobian/827937 to your computer and use it in GitHub Desktop.
Save jacobian/827937 to your computer and use it in GitHub Desktop.
An example of using many-to-many "through" to augment m2m relationships. See http://www.quora.com/How-do-you-query-with-a-condition-on-a-ManyToMany-model-in-Django for context.
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=200)
groups = models.ManyToManyField('Group', through='GroupMember', related_name='people')
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=200)
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class GroupMember(models.Model):
person = models.ForeignKey(Person, related_name='membership')
group = models.ForeignKey(Group, related_name='membership')
type = models.CharField(max_length=100)
def __unicode__(self):
return "%s is in group %s (as %s)" % (self.person, self.group, self.type)
from django.test import TestCase
from .models import Person, Group, GroupMember
class M2MThroughTest(TestCase):
def setUp(self):
# Create three people:
self.joe = Person.objects.create(name='Joe')
self.jim = Person.objects.create(name='Jim')
self.bob = Person.objects.create(name='Bob')
# And three groups:
self.jocks = Group.objects.create(name='Jocks')
self.nerds = Group.objects.create(name='Nerds')
self.skaters = Group.objects.create(name='Skaters')
# Every person is a member of every group, but
# Joe admins jocks, Jim admins nerds, and Bob admins skaters.
GroupMember.objects.create(person=self.joe, group=self.jocks, type="admin")
GroupMember.objects.create(person=self.jim, group=self.jocks, type="member")
GroupMember.objects.create(person=self.bob, group=self.jocks, type="member")
GroupMember.objects.create(person=self.joe, group=self.nerds, type="member")
GroupMember.objects.create(person=self.jim, group=self.nerds, type="admin")
GroupMember.objects.create(person=self.bob, group=self.nerds, type="member")
GroupMember.objects.create(person=self.joe, group=self.skaters, type="member")
GroupMember.objects.create(person=self.jim, group=self.skaters, type="member")
GroupMember.objects.create(person=self.bob, group=self.skaters, type="admin")
def test_unfiltered_membership(self):
# Which groups is Jim in?
jims_groups = Group.objects.filter(people=self.jim)
self.assertEqual(list(jims_groups), [self.jocks, self.nerds, self.skaters])
def test_admin_groups(self):
# But which groups does Jim admin?
jim_admins = Group.objects.filter(people=self.jim, membership__type='admin')
self.assertEqual(list(jim_admins), [self.nerds])
def test_member_groups(self):
# And which groups is Bob just a member of?
bob_membership = Group.objects.filter(people=self.bob, membership__type='member')
self.assertEqual(list(bob_membership), [self.jocks, self.nerds])
@jlmitch5
Copy link

jlmitch5 commented Jun 9, 2014

Thanks for this...helped me easily write a fix with some weird foreign key reference issues.

See: http://stackoverflow.com/questions/24127467/django-1-6-python-2-7-manytomany-not-mapping-references-to-joined-tables

@jlmitch5
Copy link

jlmitch5 commented Jun 9, 2014

Also, I think this is actually a bug...down to PR django if I'm not just being dumb. Check out that stackoverflow if you don't mind and let me know.

@osjayaprakash
Copy link

how to query all Groups a person involved in ?
Also how to query All persons in a group ?

@SamuelNata
Copy link

@osjayaprakash try this
how to query all Groups a person involved in ?
R: having the person, use person.groups as the field is declared in model.
Also how to query All persons in a group ?
R: having the group, use group.people as the related_name define in ManyToMany field.

@Allan-Nava
Copy link

Thanks for example!

@nemodev76
Copy link

gives error. this code lacks more info.

@dhirwa13
Copy link

Very helpful, thanks for the example.

@micahdanger
Copy link

Nine years later, still helpful. Thank you for this.

@MilovanTomasevic
Copy link

Nice example! 👏🏻

@prateek2211
Copy link

Thanks

@ptsteadman
Copy link

Thanks, I was stuck!

@clarkchen
Copy link

Nice Example~~
thank you for sharing

@Anjaan-g
Copy link

Really helped me a lot. Thanks for sharing.

@ahmederrami
Copy link

Thanks for sharing. Very helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment