Skip to content

Commit

Permalink
Add support for many-to-many relationships with through tables
Browse files Browse the repository at this point in the history
  • Loading branch information
paltman committed Sep 24, 2010
1 parent 61564b9 commit e3285a0
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
6 changes: 5 additions & 1 deletion milkman/dairy.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def deliver(self, the_milkman, **explicit_values):
def is_m2m(self, field):
return field in [f.name for f in self.model_class._meta.local_many_to_many]

def has_explicit_through_table(self, field):
return not field.rel.through._meta.auto_created

def set_explicit_values(self, target, explicit_values):
for k,v in explicit_values.iteritems():
if not self.is_m2m(k):
Expand All @@ -86,7 +89,8 @@ def set_local_fields(self, target, the_milkman, exclude):

def set_m2m_fields(self, target, the_milkman, exclude):
for field in self.fields_to_generate(self.model_class._meta.local_many_to_many, exclude):
setattr(target, field.name, [the_milkman.deliver(field.rel.to)])
if not self.has_explicit_through_table(field):
setattr(target, field.name, [the_milkman.deliver(field.rel.to)])

def generator_for(self, registry, field):
field_cls = type(field)
Expand Down
2 changes: 1 addition & 1 deletion testapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ class CounselingUncle(models.Model):

class EstrangedChild(models.Model):
name = models.CharField(max_length=16)
cousins = models.ManyToManyField(Uncle, through=CounselingUncle)
uncles = models.ManyToManyField(Uncle, through=CounselingUncle)
28 changes: 20 additions & 8 deletions testapp/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ def test_m2m_explicit(self):
aunt = milkman.deliver(Aunt, uncles=[uncle])
self.assertEquals(uncle, aunt.uncles.all()[0])

def test_m2m_through_model(self):
couseling_uncle = milkman.deliver(CounselingUncle)
self.assertTrue(isinstance(couseling_uncle, CounselingUncle))
self.assertEquals(couseling_uncle.cousin.uncles.all().count(), 1)
self.assertTrue(len(couseling_uncle.cousin.name) > 0)
self.assertTrue(len(couseling_uncle.uncle.name) > 0)

def test_m2m_model(self):
child = milkman.deliver(EstrangedChild)
self.assertTrue(isinstance(child, EstrangedChild))
self.assertEquals(child.uncles.all().count(), 0)
self.assertTrue(len(child.name) > 0)

def test_m2m_model_explicit_add(self):
child = milkman.deliver(EstrangedChild)
couseling_uncle = milkman.deliver(CounselingUncle, cousin=child)
self.assertTrue(isinstance(child, EstrangedChild))
self.assertEquals(child.uncles.all().count(), 1)
self.assertTrue(len(child.name) > 0)

class RandomFieldTest(unittest.TestCase):
def test_required_field(self):
root = milkman.deliver(Root)
Expand Down Expand Up @@ -116,11 +136,3 @@ def test_timefield_maker(self):
times = v.split(':')
self.assertEquals(len(times), 3)

class ManyToManyThroughTest(unittest.TestCase):
def test_through_model(self):
uncle = milkman.deliver(CounselingUncle)
self.assertTrue(isinstance(uncle, CounselingUncle))

def test_model(self):
child = milkman.deliver(EstrangedChild)
self.assertTrue(isinstance(child, EstrangedChild))

0 comments on commit e3285a0

Please sign in to comment.