django-modelcluster
django-modelcluster copied to clipboard
inherit Parentalkey + prefecth_related bug
the following case does not return the results you would expect :
class Parent(ClusterableModel):
pass
class OneChild(Parent):
parent = models.OneToOneField(to=Parent, parent_link=True,on_delete=models.CASCADE)
class ManyChild(models.Model):
parent = ParentalKey('cms.Parent', null=True, related_name='manyChild')
data = models.CharField(max_length=50)
data2 = models.CharField(max_length=50)
def populate():
Parent.objects.all().delete()
OneChild.objects.all().delete()
ManyChild.objects.all().delete()
p1 = Parent.objects.create()
p2 = Parent.objects.create()
c1 = OneChild.objects.create(parent=p1)
c2 = OneChild.objects.create(parent=p2)
m1 = ManyChild.objects.create(parent=c1,data='1',data2='a')
m1 = ManyChild.objects.create(parent=c1, data='2', data2='b')
m1 = ManyChild.objects.create(parent=c2, data='1', data2='c')
m1 = ManyChild.objects.create(parent=c2, data='2', data2='d')
def testresult():
queryset = OneChild.objects \
.prefetch_related(
Prefetch(
"manyChild",
queryset=ManyChild.objects.filter(data='1')
)
)
return [queryset.all()[0].manyChild.values(),queryset.all()[1].manyChild.values()]
populate()
print(testresult())
expected 1 result per queryset, gets all results that mach the filter. relation seems to be lost
in this case you would expect the result to be :
[<QuerySet [{'id': 1, 'parent_id': 10, 'data': '1', 'data2': 'a'}]>,<QuerySet [{'id': 3, 'parent_id': 11, 'data': '1', 'data2': 'c'}]>]
But it returns :
[<QuerySet [{'id': 1, 'parent_id': 10, 'data': '1', 'data2': 'a'},{'id': 3, 'parent_id': 11, 'data': '1', 'data2': 'c'}]>,<QuerySet [{'id': 1, 'parent_id': 10, 'data': '1', 'data2': 'a'},{'id': 3, 'parent_id': 11, 'data': '1', 'data2': 'c'}]>]
This issue doesnt appear if you use models.ForgienKey('cms.Parent', null=True, on_delete=models.CASCADE, related_name='manyChild')
instead of ParentalKey('cms.Parent', null=True, related_name='manyChild')
using this lib in combination with wagtail. but this seems to be unrelated to them
Using python 3.6 Django 2.1.2
for now i seem to be able to fix it using the following
class myRelationManager:
forceRelation2 = ["add","remove"]
def __init__(self,manager1,manager2):
self.manager1 = manager1
self.manager2 = manager2
def __getattr__(self, item):
if item in self.forceRelation2:
return getattr(self.manager2, item)
if hasattr(self.manager1,item):
return getattr(self.manager1,item)
return getattr(self.manager2, item)
class myRelatedAncestor(ChildObjectsDescriptor):
def __get__(self, instance, instance_type=None):
if instance is None:
return self
return myRelationManager(self.related_manager_cls(instance),self.child_object_manager_cls(instance))
class myParentalKey(ParentalKey):
related_accessor_class = myRelatedAncestor
Not very pritty but it works as far as i know atm