django-polymorphic
django-polymorphic copied to clipboard
One-level select_related
This is an attempt at adding support for select_related and thus closing #198. So far it has no unit tests or documentation and has mostly been tested with Graphene-Django which is where I found my need for this.
(Getting graphene-django-optimizer to work with this is the next step!)
With my limited testing it seems to work at the first level (e.g. Parent.objects.select_related('childa__related')) but not any deeper than that (e.g. Parent.objects.select_related('childa__related__childb'))
This PR is not in a mergeable state and instead is currently mostly created for bringing the discussion further for implementing select_related with a more complete solution.
You can try something like that:
from typing import List
from polymorphic.models import PolymorphicModel
from polymorphic.query import PolymorphicQuerySet
class SelectRelatedPolymorphicQuerySet(PolymorphicQuerySet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.used_select_related_cache = False
def use_select_related(self):
qs = self._clone()
qs.used_select_related_cache = True
return qs
def _clone(self, *args, **kwargs):
qs = super()._clone(*args, **kwargs)
qs.used_select_related_cache = self.used_select_related_cache
return qs
def _get_real_instances(self, base_result_objects: List[PolymorphicModel]):
if self.used_select_related_cache:
return [item.get_real_instance() for item in base_result_objects]
return super()._get_real_instances(base_result_objects)
from polymorphic.managers import PolymorphicManager
from polymorphic.models import PolymorphicModel
from vas.utils.models.polymorhic.querysets import SelectRelatedPolymorphicQuerySet
class SelectRelatedPolymorphicModel(PolymorphicModel):
class Meta:
abstract = True
objects = PolymorphicManager.from_queryset(SelectRelatedPolymorphicQuerySet)()
def get_real_instance(self):
real_model = self.get_real_instance_class()
if real_model == self.__class__:
return self
# allow to use cache:
# return getattr(self, real_model.__name__.lower())
return self._state.fields_cache[real_model.__name__.lower()] # todo