Optimization - don't do extra queries for proxy models
parent
74389bb23d
commit
58c4f6f697
|
|
@ -103,6 +103,12 @@ class PolymorphicModel(models.Model):
|
||||||
# so we use the following version, which uses the CopntentType manager cache
|
# so we use the following version, which uses the CopntentType manager cache
|
||||||
return ContentType.objects.get_for_id(self.polymorphic_ctype_id).model_class()
|
return ContentType.objects.get_for_id(self.polymorphic_ctype_id).model_class()
|
||||||
|
|
||||||
|
def get_real_concrete_instance_class_id(self):
|
||||||
|
return ContentType.objects.get_for_model(self.get_real_instance_class(), for_concrete_model=True).pk
|
||||||
|
|
||||||
|
def get_real_concrete_instance_class(self):
|
||||||
|
return ContentType.objects.get_for_model(self.get_real_instance_class(), for_concrete_model=True).model_class()
|
||||||
|
|
||||||
def get_real_instance(self):
|
def get_real_instance(self):
|
||||||
"""Normally not needed.
|
"""Normally not needed.
|
||||||
If a non-polymorphic manager (like base_objects) has been used to
|
If a non-polymorphic manager (like base_objects) has been used to
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,15 @@ from django.db.models.query import CHUNK_SIZE # this is 100 for Dj
|
||||||
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE
|
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
def transmogrify(cls, obj):
|
||||||
|
"""
|
||||||
|
Clone an object as a different class, by instantiating that class and copying the __dict__
|
||||||
|
"""
|
||||||
|
new = cls()
|
||||||
|
for k,v in obj.__dict__.items():
|
||||||
|
new.__dict__[k] = v
|
||||||
|
return new
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicQuerySet
|
### PolymorphicQuerySet
|
||||||
|
|
||||||
|
|
@ -136,6 +145,8 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
# - store objects that already have the correct class into "results"
|
# - store objects that already have the correct class into "results"
|
||||||
base_result_objects_by_id = {}
|
base_result_objects_by_id = {}
|
||||||
self_model_content_type_id = ContentType.objects.get_for_model(self.model, for_concrete_model=False).pk
|
self_model_content_type_id = ContentType.objects.get_for_model(self.model, for_concrete_model=False).pk
|
||||||
|
self_concrete_model_content_type_id = ContentType.objects.get_for_model(self.model, for_concrete_model=True).pk
|
||||||
|
|
||||||
for base_object in base_result_objects:
|
for base_object in base_result_objects:
|
||||||
ordered_id_list.append(base_object.pk)
|
ordered_id_list.append(base_object.pk)
|
||||||
|
|
||||||
|
|
@ -146,14 +157,21 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
|
|
||||||
base_result_objects_by_id[base_object.pk] = base_object
|
base_result_objects_by_id[base_object.pk] = base_object
|
||||||
|
|
||||||
# this object is not a derived object and already the real instance => store it right away
|
|
||||||
if (base_object.polymorphic_ctype_id == self_model_content_type_id):
|
if (base_object.polymorphic_ctype_id == self_model_content_type_id):
|
||||||
|
# Real class is exactly the same as base class, go straight to results
|
||||||
results[base_object.pk] = base_object
|
results[base_object.pk] = base_object
|
||||||
|
|
||||||
# this object is derived and its real instance needs to be retrieved
|
|
||||||
# => store it's id into the bin for this model type
|
|
||||||
else:
|
else:
|
||||||
idlist_per_model[base_object.get_real_instance_class()].append(base_object.pk)
|
modelclass = base_object.get_real_instance_class()
|
||||||
|
real_concrete_class_id = base_object.get_real_concrete_instance_class_id()
|
||||||
|
|
||||||
|
if real_concrete_class_id == self_concrete_model_content_type_id:
|
||||||
|
# Real and base classes share the same concrete ancestor,
|
||||||
|
# upcast it and put it in the results
|
||||||
|
results[base_object.pk] = transmogrify(modelclass, base_object)
|
||||||
|
else:
|
||||||
|
modelclass = ContentType.objects.get_for_id(real_concrete_class_id).model_class()
|
||||||
|
idlist_per_model[modelclass].append(base_object.pk)
|
||||||
|
|
||||||
# django's automatic ".pk" field does not always work correctly for
|
# django's automatic ".pk" field does not always work correctly for
|
||||||
# custom fields in derived objects (unclear yet who to put the blame on).
|
# custom fields in derived objects (unclear yet who to put the blame on).
|
||||||
|
|
@ -175,6 +193,11 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
|
|
||||||
for o in qs:
|
for o in qs:
|
||||||
o_pk = getattr(o, pk_name)
|
o_pk = getattr(o, pk_name)
|
||||||
|
real_class = o.get_real_instance_class()
|
||||||
|
|
||||||
|
# If the real class is a proxy, upcast it
|
||||||
|
if real_class != modelclass:
|
||||||
|
o = transmogrify(real_class, o)
|
||||||
|
|
||||||
if self.query.aggregates:
|
if self.query.aggregates:
|
||||||
for anno_field_name in self.query.aggregates.keys():
|
for anno_field_name in self.query.aggregates.keys():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue