Merge pull request #89 from kezabelle/bugfix/named_onetoone

Allow InheritanceManager to work with manually specified OneToOnes
This commit is contained in:
Carl Meyer 2013-10-26 16:59:23 -07:00
commit 3b5c99b093
3 changed files with 114 additions and 6 deletions

View file

@ -110,8 +110,8 @@ class InheritanceQuerySet(QuerySet):
if levels or levels is None:
for subclass in self._get_subclasses_recurse(
rel.field.model, levels=levels):
subclasses.append(rel.var_name + LOOKUP_SEP + subclass)
subclasses.append(rel.var_name)
subclasses.append(rel.get_accessor_name() + LOOKUP_SEP + subclass)
subclasses.append(rel.get_accessor_name())
return subclasses
@ -130,7 +130,7 @@ class InheritanceQuerySet(QuerySet):
if levels:
levels -= 1
while parent is not None:
ancestry.insert(0, parent.related.var_name)
ancestry.insert(0, parent.related.get_accessor_name())
if levels or levels is None:
parent = parent.related.parent_model._meta.get_ancestor_link(
self.model)

View file

@ -44,20 +44,29 @@ class InheritanceManagerTestChild1(InheritanceManagerTestParent):
objects = InheritanceManager()
class InheritanceManagerTestGrandChild1(InheritanceManagerTestChild1):
text_field = models.TextField()
class InheritanceManagerTestGrandChild1_2(InheritanceManagerTestChild1):
text_field = models.TextField()
class InheritanceManagerTestChild2(InheritanceManagerTestParent):
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
normal_field_2 = models.TextField()
class InheritanceManagerTestChild3(InheritanceManagerTestParent):
parent_ptr = models.OneToOneField(
InheritanceManagerTestParent, related_name='manual_onetoone',
parent_link=True)
class TimeStamp(TimeStampedModel):
pass

View file

@ -27,7 +27,8 @@ from model_utils.tests.models import (
TimeFrameManagerAdded, Dude, SplitFieldAbstractParent, Car, Spot,
ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked,
Tracked, TrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
InheritedTracked, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled)
InheritedTracked, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled,
InheritanceManagerTestChild3)
class GetExcerptTests(TestCase):
@ -683,6 +684,76 @@ class InheritanceManagerTests(TestCase):
self.assertEqual(1, self.get_manager().all()._get_maximum_depth())
@skipUnless(django.VERSION < (1, 6, 0), "test only applies to Django < 1.6")
def test_manually_specifying_parent_fk_only_children(self):
"""
given a Model which inherits from another Model, but also declares
the OneToOne link manually using `related_name` and `parent_link`,
ensure that the relation names and subclasses are obtained correctly.
"""
child3 = InheritanceManagerTestChild3.objects.create()
results = InheritanceManagerTestParent.objects.all().select_subclasses()
expected_objs = [self.child1, self.child2,
InheritanceManagerTestChild1(pk=self.grandchild1.pk),
InheritanceManagerTestChild1(pk=self.grandchild1_2.pk),
child3]
self.assertEqual(list(results), expected_objs)
expected_related_names = [
'inheritancemanagertestchild1',
'inheritancemanagertestchild2',
'manual_onetoone', # this was set via parent_link & related_name
]
self.assertEqual(set(results.subclasses),
set(expected_related_names))
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_manually_specifying_parent_fk_including_grandchildren(self):
"""
given a Model which inherits from another Model, but also declares
the OneToOne link manually using `related_name` and `parent_link`,
ensure that the relation names and subclasses are obtained correctly.
"""
child3 = InheritanceManagerTestChild3.objects.create()
results = InheritanceManagerTestParent.objects.all().select_subclasses()
expected_objs = [self.child1, self.child2, self.grandchild1,
self.grandchild1_2, child3]
self.assertEqual(list(results), expected_objs)
expected_related_names = [
'inheritancemanagertestchild1__inheritancemanagertestgrandchild1',
'inheritancemanagertestchild1__inheritancemanagertestgrandchild1_2',
'inheritancemanagertestchild1',
'inheritancemanagertestchild2',
'manual_onetoone', # this was set via parent_link & related_name
]
self.assertEqual(set(results.subclasses),
set(expected_related_names))
def test_manually_specifying_parent_fk_single_subclass(self):
"""
Using a string related_name when the relation is manually defined
instead of implicit should still work in the same way.
"""
related_name = 'manual_onetoone'
child3 = InheritanceManagerTestChild3.objects.create()
results = InheritanceManagerTestParent.objects.all().select_subclasses(related_name)
expected_objs = [InheritanceManagerTestParent(pk=self.child1.pk),
InheritanceManagerTestParent(pk=self.child2.pk),
InheritanceManagerTestParent(pk=self.grandchild1.pk),
InheritanceManagerTestParent(pk=self.grandchild1_2.pk),
child3]
self.assertEqual(list(results), expected_objs)
expected_related_names = [related_name]
self.assertEqual(set(results.subclasses),
set(expected_related_names))
class InheritanceManagerUsingModelsTests(TestCase):
def setUp(self):
@ -731,6 +802,7 @@ class InheritanceManagerUsingModelsTests(TestCase):
objs = InheritanceManagerTestParent.objects.select_subclasses().order_by('pk')
objsmodels = InheritanceManagerTestParent.objects.select_subclasses(
InheritanceManagerTestChild1, InheritanceManagerTestChild2,
InheritanceManagerTestChild3,
InheritanceManagerTestGrandChild1,
InheritanceManagerTestGrandChild1_2).order_by('pk')
self.assertEqual(set(objs.subclasses), set(objsmodels.subclasses))
@ -751,11 +823,15 @@ class InheritanceManagerUsingModelsTests(TestCase):
objs = InheritanceManagerTestParent.objects.select_subclasses().order_by('pk')
if django.VERSION >= (1, 6, 0):
models = (InheritanceManagerTestChild1, InheritanceManagerTestChild2,
models = (InheritanceManagerTestChild1,
InheritanceManagerTestChild2,
InheritanceManagerTestChild3,
InheritanceManagerTestGrandChild1,
InheritanceManagerTestGrandChild1_2)
else:
models = (InheritanceManagerTestChild1, InheritanceManagerTestChild2)
models = (InheritanceManagerTestChild1,
InheritanceManagerTestChild2,
InheritanceManagerTestChild3)
objsmodels = InheritanceManagerTestParent.objects.select_subclasses(
*models).order_by('pk')
@ -873,6 +949,29 @@ class InheritanceManagerUsingModelsTests(TestCase):
], list(objs))
def test_manually_specifying_parent_fk_only_specific_child(self):
"""
given a Model which inherits from another Model, but also declares
the OneToOne link manually using `related_name` and `parent_link`,
ensure that the relation names and subclasses are obtained correctly.
"""
child3 = InheritanceManagerTestChild3.objects.create()
results = InheritanceManagerTestParent.objects.all().select_subclasses(
InheritanceManagerTestChild3)
expected_objs = [InheritanceManagerTestParent(pk=self.parent1.pk),
InheritanceManagerTestParent(pk=self.child1.pk),
InheritanceManagerTestParent(pk=self.child2.pk),
InheritanceManagerTestParent(pk=self.grandchild1.pk),
InheritanceManagerTestParent(pk=self.grandchild1_2.pk),
child3]
self.assertEqual(list(results), expected_objs)
expected_related_names = ['manual_onetoone']
self.assertEqual(set(results.subclasses),
set(expected_related_names))
class InheritanceManagerRelatedTests(InheritanceManagerTests):
def setUp(self):