From fd0ed96c1ad4a09713dea74c1a29cac4ade4c127 Mon Sep 17 00:00:00 2001 From: hottwaj Date: Wed, 19 Feb 2014 10:56:02 +0000 Subject: [PATCH] Fixed bugs in superclass/subclass field link processingso that this can cope with proxy models, as well as parent_link and related_name links to parents. Added a test case for testing parent_link and related_name links to parent. All tests pass should pass now (at least they do for me on django 1.5 and python 2.7) --- polymorphic/polymorphic_model.py | 31 +++++++++++++++++-------------- polymorphic/tests.py | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 14 deletions(-) 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):