Assuming I have the following models:

class SomeSuperClass(models.Model):
    ...

class SomeSubClassA(SomeSuperClass)
    ...

class SomeSubClassB(SomeSuperClass)
    ...

class SomeConnector(models.Model):
    reference = models.ForeignKey(SomeSuperClass, on_delete=models.CASCADE)
    ...

Now what I would want to have is somehow when iterating over objects of SomeConnector I always want to have right away objects of the respective subclasses, not of the superclasses. E.g.

for sc in SomeConnector.objects.all():

    # somehow get the correct subclass of this `reference` field here,
    # assuming it to be callable under sc.reference_correct_subclass:
    print(sc.reference_correct_subclass.__class__.__name__)

could produce for example:

'SomeSubClassA'
'SomeSubClassB'
'SomeSubClassA'
'SomeSubClassA'

But never should an object of the superclass be used.

I know of django-model-utils and I could do something similiar by querying directly on the superclass, like this:

SomeSuperClass.objects_inheritance.select_subclasses()

where objects_inheritance is the InheritanceManager attached to SomeSuperClass. However I could not figure out yet how to reproduce this when the superclass is used as foreign key in another class which I want to use for querying.

1

There are 1 best solutions below

0
On BEST ANSWER

I could get it working by subclasing the ForeignKey field with an additionally sublcassed ForwardManyToOneDescriptor as I found in this thread.

The code for this subclassing would be this:

from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor

class InheritanceForwardManyToOneDescriptor(ForwardManyToOneDescriptor):
    def get_queryset(self, **hints):
        return self.field.remote_field.model.objects_inheritance.db_manager(hints=hints).select_subclasses()


class InheritanceForeignKey(models.ForeignKey):
    forward_related_accessor_class = InheritanceForwardManyToOneDescriptor

And to use it in my code example, then this would be integrated like this:

class SomeConnector(models.Model):
    reference = InheritanceForeignKey(SomeSuperClass, on_delete=models.CASCADE)