Commits

russ...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed 1a5661f

Migrated model_inheritance_regress doctests. Thanks to Gregor Müllegger for the patch.

  • Participants
  • Parent commits 593ff0a

Comments (0)

Files changed (2)

File tests/regressiontests/model_inheritance_regress/models.py

-"""
-Regression tests for Model inheritance behaviour.
-"""
-
 import datetime
 
 from django.db import models
 
 class MessyBachelorParty(BachelorParty):
     pass
-
-__test__ = {'API_TESTS':"""
-# Regression for #7350, #7202
-# Check that when you create a Parent object with a specific reference to an
-# existent child instance, saving the Parent doesn't duplicate the child. This
-# behaviour is only activated during a raw save - it is mostly relevant to
-# deserialization, but any sort of CORBA style 'narrow()' API would require a
-# similar approach.
-
-# Create a child-parent-grandparent chain
->>> place1 = Place(name="Guido's House of Pasta", address='944 W. Fullerton')
->>> place1.save_base(raw=True)
->>> restaurant = Restaurant(place_ptr=place1, serves_hot_dogs=True, serves_pizza=False)
->>> restaurant.save_base(raw=True)
->>> italian_restaurant = ItalianRestaurant(restaurant_ptr=restaurant, serves_gnocchi=True)
->>> italian_restaurant.save_base(raw=True)
-
-# Create a child-parent chain with an explicit parent link
->>> place2 = Place(name='Main St', address='111 Main St')
->>> place2.save_base(raw=True)
->>> park = ParkingLot(parent=place2, capacity=100)
->>> park.save_base(raw=True)
-
-# Check that no extra parent objects have been created.
->>> Place.objects.all()
-[<Place: Guido's House of Pasta the place>, <Place: Main St the place>]
-
->>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_hot_dogs', True)]]
-True
-
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_gnocchi', True), ('serves_hot_dogs', True)]]
-True
-
->>> dicts = ParkingLot.objects.values('name','capacity')
->>> [sorted(d.items()) for d in dicts]
-[[('capacity', 100), ('name', u'Main St')]]
-
-# You can also update objects when using a raw save.
->>> place1.name = "Guido's All New House of Pasta"
->>> place1.save_base(raw=True)
-
->>> restaurant.serves_hot_dogs = False
->>> restaurant.save_base(raw=True)
-
->>> italian_restaurant.serves_gnocchi = False
->>> italian_restaurant.save_base(raw=True)
-
->>> place2.name='Derelict lot'
->>> place2.save_base(raw=True)
-
->>> park.capacity = 50
->>> park.save_base(raw=True)
-
-# No extra parent objects after an update, either.
->>> Place.objects.all()
-[<Place: Derelict lot the place>, <Place: Guido's All New House of Pasta the place>]
-
->>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_hot_dogs', False)]]
-True
-
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
-True
-
->>> dicts = ParkingLot.objects.values('name','capacity')
->>> [sorted(d.items()) for d in dicts]
-[[('capacity', 50), ('name', u'Derelict lot')]]
-
-# If you try to raw_save a parent attribute onto a child object,
-# the attribute will be ignored.
-
->>> italian_restaurant.name = "Lorenzo's Pasta Hut"
->>> italian_restaurant.save_base(raw=True)
-
-# Note that the name has not changed
-# - name is an attribute of Place, not ItalianRestaurant
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
-True
-
-# Regressions tests for #7105: dates() queries should be able to use fields
-# from the parent model as easily as the child.
->>> obj = Child.objects.create(name='child', created=datetime.datetime(2008, 6, 26, 17, 0, 0))
->>> Child.objects.dates('created', 'month')
-[datetime.datetime(2008, 6, 1, 0, 0)]
-
-# Regression test for #7276: calling delete() on a model with multi-table
-# inheritance should delete the associated rows from any ancestor tables, as
-# well as any descendent objects.
-
->>> ident = ItalianRestaurant.objects.all()[0].id
->>> Place.objects.get(pk=ident)
-<Place: Guido's All New House of Pasta the place>
->>> xx = Restaurant.objects.create(name='a', address='xx', serves_hot_dogs=True, serves_pizza=False)
-
-# This should delete both Restuarants, plus the related places, plus the ItalianRestaurant.
->>> Restaurant.objects.all().delete()
-
->>> Place.objects.get(pk=ident)
-Traceback (most recent call last):
-...
-DoesNotExist: Place matching query does not exist.
-
->>> ItalianRestaurant.objects.get(pk=ident)
-Traceback (most recent call last):
-...
-DoesNotExist: ItalianRestaurant matching query does not exist.
-
-# Regression test for #6755
->>> r = Restaurant(serves_pizza=False)
->>> r.save()
->>> r.id == r.place_ptr_id
-True
->>> orig_id = r.id
->>> r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
->>> r.save()
->>> r.id == orig_id
-True
->>> r.id == r.place_ptr_id
-True
-
-# Regression test for #7488. This looks a little crazy, but it's the equivalent
-# of what the admin interface has to do for the edit-inline case.
->>> Supplier.objects.filter(restaurant=Restaurant(name='xx', address='yy'))
-[]
-
-# Regression test for #11764.
->>> for w in Wholesaler.objects.all().select_related():
-...     print w
-
-# Regression test for #7853
-# If the parent class has a self-referential link, make sure that any updates
-# to that link via the child update the right table.
-
->>> obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
->>> obj.delete()
-
-# Regression tests for #8076 - get_(next/previous)_by_date should work.
->>> c1 = ArticleWithAuthor(headline='ArticleWithAuthor 1', author="Person 1", pub_date=datetime.datetime(2005, 8, 1, 3, 0))
->>> c1.save()
->>> c2 = ArticleWithAuthor(headline='ArticleWithAuthor 2', author="Person 2", pub_date=datetime.datetime(2005, 8, 1, 10, 0))
->>> c2.save()
->>> c3 = ArticleWithAuthor(headline='ArticleWithAuthor 3', author="Person 3", pub_date=datetime.datetime(2005, 8, 2))
->>> c3.save()
-
->>> c1.get_next_by_pub_date()
-<ArticleWithAuthor: ArticleWithAuthor 2>
->>> c2.get_next_by_pub_date()
-<ArticleWithAuthor: ArticleWithAuthor 3>
->>> c3.get_next_by_pub_date()
-Traceback (most recent call last):
-    ...
-DoesNotExist: ArticleWithAuthor matching query does not exist.
->>> c3.get_previous_by_pub_date()
-<ArticleWithAuthor: ArticleWithAuthor 2>
->>> c2.get_previous_by_pub_date()
-<ArticleWithAuthor: ArticleWithAuthor 1>
->>> c1.get_previous_by_pub_date()
-Traceback (most recent call last):
-    ...
-DoesNotExist: ArticleWithAuthor matching query does not exist.
-
-# Regression test for #8825: Make sure all inherited fields (esp. m2m fields, in
-# this case) appear on the child class.
->>> M2MChild.objects.filter(articles__isnull=False)
-[]
-
-# All fields from an ABC, including those inherited non-abstractly should be
-# available on child classes (#7588). Creating this instance should work
-# without error.
->>> _ = QualityControl.objects.create(headline="Problems in Django", pub_date=datetime.datetime.now(), quality=10, assignee="adrian")
-
-# Ordering should not include any database column more than once (this is most
-# likely to ocurr naturally with model inheritance, so we check it here).
-# Regression test for #9390. This necessarily pokes at the SQL string for the
-# query, since the duplicate problems are only apparent at that late stage.
->>> qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
->>> sql = qs.query.get_compiler(qs.db).as_sql()[0]
->>> fragment = sql[sql.find('ORDER BY'):]
->>> pos = fragment.find('pub_date')
->>> fragment.find('pub_date', pos + 1) == -1
-True
-
-# It is possible to call update() and only change a field in an ancestor model
-# (regression test for #10362).
->>> article = ArticleWithAuthor.objects.create(author="fred", headline="Hey there!", pub_date = datetime.datetime(2009, 3, 1, 8, 0, 0))
->>> ArticleWithAuthor.objects.filter(author="fred").update(headline="Oh, no!")
-1
->>> ArticleWithAuthor.objects.filter(pk=article.pk).update(headline="Oh, no!")
-1
-
->>> DerivedM.objects.create(customPK=44, base_name="b1", derived_name="d1")
-<DerivedM: PK = 44, base_name = b1, derived_name = d1>
->>> DerivedM.objects.all()
-[<DerivedM: PK = 44, base_name = b1, derived_name = d1>]
-
-# Regression tests for #10406
-
-# If there's a one-to-one link between a child model and the parent and no
-# explicit pk declared, we can use the one-to-one link as the pk on the child.
-# The ParkingLot2 model shows this behaviour.
->>> ParkingLot2._meta.pk.name
-"parent"
-
-# However, the connector from child to parent need not be the pk on the child
-# at all.
->>> ParkingLot3._meta.pk.name
-"primary_key"
->>> ParkingLot3._meta.get_ancestor_link(Place).name  # the child->parent link
-"parent"
-
-# Check that many-to-many relations defined on an abstract base class
-# are correctly inherited (and created) on the child class.
->>> p1 = Person.objects.create(name='Alice')
->>> p2 = Person.objects.create(name='Bob')
->>> p3 = Person.objects.create(name='Carol')
->>> p4 = Person.objects.create(name='Dave')
-
->>> birthday = BirthdayParty.objects.create(name='Birthday party for Alice')
->>> birthday.attendees = [p1, p3]
-
->>> bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
->>> bachelor.attendees = [p2, p4]
-
->>> print p1.birthdayparty_set.all()
-[<BirthdayParty: Birthday party for Alice>]
-
->>> print p1.bachelorparty_set.all()
-[]
-
->>> print p2.bachelorparty_set.all()
-[<BachelorParty: Bachelor party for Bob>]
-
-# Check that a subclass of a subclass of an abstract model
-# doesn't get it's own accessor.
->>> p2.messybachelorparty_set.all()
-Traceback (most recent call last):
-...
-AttributeError: 'Person' object has no attribute 'messybachelorparty_set'
-
-# ... but it does inherit the m2m from it's parent
->>> messy = MessyBachelorParty.objects.create(name='Bachelor party for Dave')
->>> messy.attendees = [p4]
-
->>> p4.bachelorparty_set.all()
-[<BachelorParty: Bachelor party for Bob>, <BachelorParty: Bachelor party for Dave>]
-
-"""}
-

File tests/regressiontests/model_inheritance_regress/tests.py

+"""
+Regression tests for Model inheritance behaviour.
+"""
+
+import datetime
+from django.test import TestCase
+from regressiontests.model_inheritance_regress.models import (
+    Place, Restaurant, ItalianRestaurant, ParkingLot, ParkingLot2,
+    ParkingLot3, Supplier, Wholesaler, Child, SelfRefChild, ArticleWithAuthor,
+    M2MChild, QualityControl, DerivedM, Person, BirthdayParty, BachelorParty,
+    MessyBachelorParty)
+
+class ModelInheritanceTest(TestCase):
+    def test_model_inheritance(self):
+        # Regression for #7350, #7202
+        # Check that when you create a Parent object with a specific reference
+        # to an existent child instance, saving the Parent doesn't duplicate
+        # the child. This behaviour is only activated during a raw save - it
+        # is mostly relevant to deserialization, but any sort of CORBA style
+        # 'narrow()' API would require a similar approach.
+
+        # Create a child-parent-grandparent chain
+        place1 = Place(
+            name="Guido's House of Pasta",
+            address='944 W. Fullerton')
+        place1.save_base(raw=True)
+        restaurant = Restaurant(
+            place_ptr=place1,
+            serves_hot_dogs=True,
+            serves_pizza=False)
+        restaurant.save_base(raw=True)
+        italian_restaurant = ItalianRestaurant(
+            restaurant_ptr=restaurant,
+            serves_gnocchi=True)
+        italian_restaurant.save_base(raw=True)
+
+        # Create a child-parent chain with an explicit parent link
+        place2 = Place(name='Main St', address='111 Main St')
+        place2.save_base(raw=True)
+        park = ParkingLot(parent=place2, capacity=100)
+        park.save_base(raw=True)
+
+        # Check that no extra parent objects have been created.
+        places = list(Place.objects.all())
+        self.assertEqual(places, [place1, place2])
+
+        dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
+        self.assertEqual(dicts, [{
+            'name': u"Guido's House of Pasta",
+            'serves_hot_dogs': True
+        }])
+
+        dicts = list(ItalianRestaurant.objects.values(
+            'name','serves_hot_dogs','serves_gnocchi'))
+        self.assertEqual(dicts, [{
+            'name': u"Guido's House of Pasta",
+            'serves_gnocchi': True,
+            'serves_hot_dogs': True,
+        }])
+
+        dicts = list(ParkingLot.objects.values('name','capacity'))
+        self.assertEqual(dicts, [{
+            'capacity': 100,
+            'name': u'Main St',
+        }])
+
+        # You can also update objects when using a raw save.
+        place1.name = "Guido's All New House of Pasta"
+        place1.save_base(raw=True)
+
+        restaurant.serves_hot_dogs = False
+        restaurant.save_base(raw=True)
+
+        italian_restaurant.serves_gnocchi = False
+        italian_restaurant.save_base(raw=True)
+
+        place2.name='Derelict lot'
+        place2.save_base(raw=True)
+
+        park.capacity = 50
+        park.save_base(raw=True)
+
+        # No extra parent objects after an update, either.
+        places = list(Place.objects.all())
+        self.assertEqual(places, [place2, place1])
+        self.assertEqual(places[0].name, 'Derelict lot')
+        self.assertEqual(places[1].name, "Guido's All New House of Pasta")
+
+        dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
+        self.assertEqual(dicts, [{
+            'name': u"Guido's All New House of Pasta",
+            'serves_hot_dogs': False,
+        }])
+
+        dicts = list(ItalianRestaurant.objects.values(
+            'name', 'serves_hot_dogs', 'serves_gnocchi'))
+        self.assertEqual(dicts, [{
+            'name': u"Guido's All New House of Pasta",
+            'serves_gnocchi': False,
+            'serves_hot_dogs': False,
+        }])
+
+        dicts = list(ParkingLot.objects.values('name','capacity'))
+        self.assertEqual(dicts, [{
+            'capacity': 50,
+            'name': u'Derelict lot',
+        }])
+
+        # If you try to raw_save a parent attribute onto a child object,
+        # the attribute will be ignored.
+
+        italian_restaurant.name = "Lorenzo's Pasta Hut"
+        italian_restaurant.save_base(raw=True)
+
+        # Note that the name has not changed
+        # - name is an attribute of Place, not ItalianRestaurant
+        dicts = list(ItalianRestaurant.objects.values(
+            'name','serves_hot_dogs','serves_gnocchi'))
+        self.assertEqual(dicts, [{
+            'name': u"Guido's All New House of Pasta",
+            'serves_gnocchi': False,
+            'serves_hot_dogs': False,
+        }])
+
+    def test_issue_7105(self):
+        # Regressions tests for #7105: dates() queries should be able to use
+        # fields from the parent model as easily as the child.
+        obj = Child.objects.create(
+            name='child',
+            created=datetime.datetime(2008, 6, 26, 17, 0, 0))
+        dates = list(Child.objects.dates('created', 'month'))
+        self.assertEqual(dates, [datetime.datetime(2008, 6, 1, 0, 0)])
+
+    def test_issue_7276(self):
+        # Regression test for #7276: calling delete() on a model with
+        # multi-table inheritance should delete the associated rows from any
+        # ancestor tables, as well as any descendent objects.
+        place1 = Place(
+            name="Guido's House of Pasta",
+            address='944 W. Fullerton')
+        place1.save_base(raw=True)
+        restaurant = Restaurant(
+            place_ptr=place1,
+            serves_hot_dogs=True,
+            serves_pizza=False)
+        restaurant.save_base(raw=True)
+        italian_restaurant = ItalianRestaurant(
+            restaurant_ptr=restaurant,
+            serves_gnocchi=True)
+        italian_restaurant.save_base(raw=True)
+
+        ident = ItalianRestaurant.objects.all()[0].id
+        self.assertEqual(Place.objects.get(pk=ident), place1)
+        xx = Restaurant.objects.create(
+            name='a',
+            address='xx',
+            serves_hot_dogs=True,
+            serves_pizza=False)
+
+        # This should delete both Restuarants, plus the related places, plus
+        # the ItalianRestaurant.
+        Restaurant.objects.all().delete()
+
+        self.assertRaises(
+            Place.DoesNotExist,
+            Place.objects.get,
+            pk=ident)
+        self.assertRaises(
+            ItalianRestaurant.DoesNotExist,
+            ItalianRestaurant.objects.get,
+            pk=ident)
+
+    def test_issue_6755(self):
+        """
+        Regression test for #6755
+        """
+        r = Restaurant(serves_pizza=False)
+        r.save()
+        self.assertEqual(r.id, r.place_ptr_id)
+        orig_id = r.id
+        r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
+        r.save()
+        self.assertEqual(r.id, orig_id)
+        self.assertEqual(r.id, r.place_ptr_id)
+
+    def test_issue_7488(self):
+        # Regression test for #7488. This looks a little crazy, but it's the
+        # equivalent of what the admin interface has to do for the edit-inline
+        # case.
+        suppliers = Supplier.objects.filter(
+            restaurant=Restaurant(name='xx', address='yy'))
+        suppliers = list(suppliers)
+        self.assertEqual(suppliers, [])
+
+    def test_issue_11764(self):
+        """
+        Regression test for #11764
+        """
+        wholesalers = list(Wholesaler.objects.all().select_related())
+        self.assertEqual(wholesalers, [])
+
+    def test_issue_7853(self):
+        """
+        Regression test for #7853
+        If the parent class has a self-referential link, make sure that any
+        updates to that link via the child update the right table.
+        """
+        obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
+        obj.delete()
+
+    def test_get_next_previous_by_date(self):
+        """
+        Regression tests for #8076
+        get_(next/previous)_by_date should work
+        """
+        c1 = ArticleWithAuthor(
+            headline='ArticleWithAuthor 1',
+            author="Person 1",
+            pub_date=datetime.datetime(2005, 8, 1, 3, 0))
+        c1.save()
+        c2 = ArticleWithAuthor(
+            headline='ArticleWithAuthor 2',
+            author="Person 2",
+            pub_date=datetime.datetime(2005, 8, 1, 10, 0))
+        c2.save()
+        c3 = ArticleWithAuthor(
+            headline='ArticleWithAuthor 3',
+            author="Person 3",
+            pub_date=datetime.datetime(2005, 8, 2))
+        c3.save()
+
+        self.assertEqual(c1.get_next_by_pub_date(), c2)
+        self.assertEqual(c2.get_next_by_pub_date(), c3)
+        self.assertRaises(
+            ArticleWithAuthor.DoesNotExist,
+            c3.get_next_by_pub_date)
+        self.assertEqual(c3.get_previous_by_pub_date(), c2)
+        self.assertEqual(c2.get_previous_by_pub_date(), c1)
+        self.assertRaises(
+            ArticleWithAuthor.DoesNotExist,
+            c1.get_previous_by_pub_date)
+
+    def test_inherited_fields(self):
+        """
+        Regression test for #8825 and #9390
+        Make sure all inherited fields (esp. m2m fields, in this case) appear
+        on the child class.
+        """
+        m2mchildren = list(M2MChild.objects.filter(articles__isnull=False))
+        self.assertEqual(m2mchildren, [])
+
+        # Ordering should not include any database column more than once (this
+        # is most likely to ocurr naturally with model inheritance, so we
+        # check it here). Regression test for #9390. This necessarily pokes at
+        # the SQL string for the query, since the duplicate problems are only
+        # apparent at that late stage.
+        qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
+        sql = qs.query.get_compiler(qs.db).as_sql()[0]
+        fragment = sql[sql.find('ORDER BY'):]
+        pos = fragment.find('pub_date')
+        self.assertEqual(fragment.find('pub_date', pos + 1), -1)
+
+    def test_queryset_update_on_parent_model(self):
+        """
+        Regression test for #10362
+        It is possible to call update() and only change a field in
+        an ancestor model.
+        """
+        article = ArticleWithAuthor.objects.create(
+            author="fred",
+            headline="Hey there!",
+            pub_date=datetime.datetime(2009, 3, 1, 8, 0, 0))
+        update = ArticleWithAuthor.objects.filter(
+            author="fred").update(headline="Oh, no!")
+        self.assertEqual(update, 1)
+        update = ArticleWithAuthor.objects.filter(
+            pk=article.pk).update(headline="Oh, no!")
+        self.assertEqual(update, 1)
+
+        derivedm1 = DerivedM.objects.create(
+            customPK=44,
+            base_name="b1",
+            derived_name="d1")
+        self.assertEqual(derivedm1.customPK, 44)
+        self.assertEqual(derivedm1.base_name, 'b1')
+        self.assertEqual(derivedm1.derived_name, 'd1')
+        derivedms = list(DerivedM.objects.all())
+        self.assertEqual(derivedms, [derivedm1])
+
+    def test_use_explicit_o2o_to_parent_as_pk(self):
+        """
+        Regression tests for #10406
+        If there's a one-to-one link between a child model and the parent and
+        no explicit pk declared, we can use the one-to-one link as the pk on
+        the child.
+        """
+        self.assertEqual(ParkingLot2._meta.pk.name, "parent")
+
+        # However, the connector from child to parent need not be the pk on
+        # the child at all.
+        self.assertEqual(ParkingLot3._meta.pk.name, "primary_key")
+        # the child->parent link
+        self.assertEqual(
+            ParkingLot3._meta.get_ancestor_link(Place).name,
+            "parent")
+
+    def test_all_fields_from_abstract_base_class(self):
+        """
+        Regression tests for #7588
+        """
+        # All fields from an ABC, including those inherited non-abstractly
+        # should be available on child classes (#7588). Creating this instance
+        # should work without error.
+        QualityControl.objects.create(
+            headline="Problems in Django",
+            pub_date=datetime.datetime.now(),
+            quality=10,
+            assignee="adrian")
+
+    def test_abstract_base_class_m2m_relation_inheritance(self):
+        # Check that many-to-many relations defined on an abstract base class
+        # are correctly inherited (and created) on the child class.
+        p1 = Person.objects.create(name='Alice')
+        p2 = Person.objects.create(name='Bob')
+        p3 = Person.objects.create(name='Carol')
+        p4 = Person.objects.create(name='Dave')
+
+        birthday = BirthdayParty.objects.create(
+            name='Birthday party for Alice')
+        birthday.attendees = [p1, p3]
+
+        bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
+        bachelor.attendees = [p2, p4]
+
+        parties = list(p1.birthdayparty_set.all())
+        self.assertEqual(parties, [birthday])
+
+        parties = list(p1.bachelorparty_set.all())
+        self.assertEqual(parties, [])
+
+        parties = list(p2.bachelorparty_set.all())
+        self.assertEqual(parties, [bachelor])
+
+        # Check that a subclass of a subclass of an abstract model doesn't get
+        # it's own accessor.
+        self.assertFalse(hasattr(p2, 'messybachelorparty_set'))
+
+        # ... but it does inherit the m2m from it's parent
+        messy = MessyBachelorParty.objects.create(
+            name='Bachelor party for Dave')
+        messy.attendees = [p4]
+        messy_parent = messy.bachelorparty_ptr
+
+        parties = list(p4.bachelorparty_set.all())
+        self.assertEqual(parties, [bachelor, messy_parent])