diff --git a/polymorphic/polymorphic_model.py b/polymorphic/polymorphic_model.py index c283841..10e95a2 100644 --- a/polymorphic/polymorphic_model.py +++ b/polymorphic/polymorphic_model.py @@ -22,7 +22,7 @@ from django.utils import six from .base import PolymorphicModelBase from .manager import PolymorphicManager from .query_translate import translate_polymorphic_Q_object - +import pdb ################################################################################### ### PolymorphicModel @@ -185,22 +185,25 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)): def add_all_super_models(model, result): for super_cls, field_to_super in model._meta.parents.iteritems(): - field_name = field_to_super.name #the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link' - add_model_if_regular(super_cls, field_name, result) - add_all_super_models(super_cls, result) + if field_to_super is not None: #if not a link to a proxy model + field_name = field_to_super.name #the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link' + add_model_if_regular(super_cls, field_name, result) + add_all_super_models(super_cls, result) def add_all_sub_models(super_cls, result): for sub_cls in super_cls.__subclasses__(): #go through all subclasses of model - field_to_super = sub_cls._meta.parents[super_cls] #get the field that links sub_cls to super_cls - super_to_sub_related_field = field_to_super.rel - if super_to_sub_related_field.related_name is None: - #if related name is None the related field is the name of the subclass - to_subclass_fieldname = sub_cls.__name__.lower() - else: - #otherwise use the given related name - to_subclass_fieldname = super_to_sub_related_field.related_name - - add_model_if_regular(sub_cls, to_subclass_fieldname, result) + if super_cls in sub_cls._meta.parents: #super_cls may not be in sub_cls._meta.parents if super_cls is a proxy model + field_to_super = sub_cls._meta.parents[super_cls] #get the field that links sub_cls to super_cls + if field_to_super is not None: # if filed_to_super is not a link to a proxy model + super_to_sub_related_field = field_to_super.rel + if super_to_sub_related_field.related_name is None: + #if related name is None the related field is the name of the subclass + to_subclass_fieldname = sub_cls.__name__.lower() + else: + #otherwise use the given related name + to_subclass_fieldname = super_to_sub_related_field.related_name + + add_model_if_regular(sub_cls, to_subclass_fieldname, result) result = {} add_all_super_models(self.__class__, result) diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 376f0f3..6177a49 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -245,6 +245,10 @@ class ProxyModelB(ProxyModelBase): class RelatedNameClash(ShowFieldType, PolymorphicModel): ctype = models.ForeignKey(ContentType, null=True, editable=False) +#class with a parent_link to superclass, and a related_name back to subclass +class TestParentLinkAndRelatedName(ModelShow1_plain): + superclass = models.OneToOneField(ModelShow1_plain, parent_link=True, related_name = 'related_name_subclass') + class PolymorphicTests(TestCase): """ @@ -767,6 +771,24 @@ class PolymorphicTests(TestCase): o = InitTestModelSubclass.objects.create() self.assertEqual(o.bar, 'XYZ') + def test_parent_link_and_related_name(self): + t = TestParentLinkAndRelatedName(field1 = "TestParentLinkAndRelatedName") + t.save() + p = ModelShow1_plain.objects.get(field1 = "TestParentLinkAndRelatedName") + + #check that p is equal to the + self.assertIsInstance(p, TestParentLinkAndRelatedName) + self.assertEqual(p, t) + + #check that the accessors to parent and sublass work correctly and return the right object + p = ModelShow1_plain.objects.non_polymorphic().get(field1 = "TestParentLinkAndRelatedName") + self.assertNotEqual(p, t) #p should be Plain1 and t TestParentLinkAndRelatedName, so not equal + self.assertEqual(p, t.superclass) + self.assertEqual(p.related_name_subclass, t) + + #test that we can delete t + t.delete() + class RegressionTests(TestCase):