Search code examples
django-modelsabstract-classsubclass

Subclassing model classes and overriding base methods


I would like to have a Django model 'Owners' with subclasses 'Industry' and 'Household' in such a way that I can iterate over the base class 'Owners' to perform an action which is overridden in each subclass.

My code would be something like this:

"" class Owner(models.Model): def dothis(self): print ('base class dothis was called' )

class Industry(Owner):
    size=models.IntegerField(default=1)
    def dothis(self):
        print(f'Industry dothis says {size}')

class Household(Owner):
    population=models.IntegerField(default=1)
    def dothis(self):
        print (f'Household dothis says  {population}')

def do():
    industry=Industry(size=1)
    industry.save()
    household=Household(population=2)
    household.save()
    for owner in Owner.objects.all():
        owner.dothis()

"" This code always invokes the 'dothis()' method of the base class

I guess this should be done by making Owner an abstract class

Since I haven't yet delved into the intricacies of creating abstract classes I'm hopin there is either (1) a standard way to make 'Owner' an abstract class (2) a workaround

When I try to create Owner as an abstract class, Django says it is non-iterable. If I try to inherit both from ABCMeta or ABC and from 'models.Model' I get the apparently Infamous message "" metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases "" I've looked at this thread

How to create abstract properties in python abstract classes?

but it's a bit above me at my present knowledge level.

Pointers to other threads, or solutions, would be appreciated.


Solution

  • This code always invokes the dothis() method of the base class

    Yes, Django's Owner.objects.all() will query the table for the Owner table only, and produce Owner objects, even if these object originate out of a subclass of Owner, so the database-to-objects functionality is not bijective.

    You can do this with django-polymorphic [pypi], which will look for all model subclasses, and then produce LEFT OUTER JOINs for each table that is a subclass.

    But as you probably can guess, this will result in some nice queries, and actually shows a more fundamental problem: inheritance and relational databases often don't work out very well. The modeling of polymorphism in the database is also not very "clean": for example it would strictly speaking be possible for to represent the same object as both Industry and Household in the database, and there is no way to prevent that the data in the database thus maps to an "invalid" inheritance pattern.

    It thus might not be ideal to use inheritance at all.