Django multi-table inheritance, how to know which is the child class of a model?
To the best of my knowledge there isn't a Django built-in way to do this.
However, given acc=account.object.get(pk=29)
, you can use:
try: typeA = acc.accounttypeA # acc is typeAexcept accounttypeA.DoesNotExist: # acc should be typeB if account only has typeA and typeB subclassestry: typeB = acc.accounttypeB # acc is typeBexcept accounttypeB.DoesNotExist: # acc should be typeA if account only has typeA and typeB subclasses
my solution was based on this
class account(models.Model): name = models…… def cast(self): """ This method is quite handy, it converts "self" into its correct child class. For example: .. code-block:: python class Fruit(models.Model): name = models.CharField() class Apple(Fruit): pass fruit = Fruit.objects.get(name='Granny Smith') apple = fruit.cast() :return self: A casted child class of self """ for name in dir(self): try: attr = getattr(self, name) if isinstance(attr, self.__class__) and type(attr) != type(self): return attr except: pass @staticmethod def allPossibleAccountTypes(): #this returns a list of all the subclasses of account (i.e. accounttypeA, accounttypeB etc) return [str(subClass).split('.')[-1][:-2] for subClass in account.__subclasses__()] def accountType(self): try: if type(self.cast()) == NoneType: #it is a child return self.__class__.__name__ else: #it is a parent, i.e. an account return str(type(self.cast())).split('.')[-1][:-2] except: logger.exception() accountType.short_description = "Account type"class accounttypeA(account): balance = models.float….. def addToBalance(self, value): self.balance += valueclass accounttypeB(account): balance = models.int…. # NOTE this
Django adds to class account
two fields: accounttypea
and accounttypeb
. If you have accounttypeB
object with pk=42, you can access from parent like this:
account.objects.get(pk=42).accounttypeb>>> <accounttypeB instance>
You can add CharField to parent model with actual child-type for every child, and then use getattr
, if there are a lot of child models (it may be better than a lot of try .. except xxx.DoesNotExist
blocks).
class account(models.Model): name = models…… cls = CharField(...) def ext(self): return getattr(self, self.cls.lower())class accounttypeA(account): balance = models.float….. def addToBalance(self, value): self.balance += valueclass accounttypeB(account): balance = models.int…. # NOTE this def addToBalance(self, value): value = do_some_thing_with_value(value) # NOTE this self.balance += value# exampleaccounttypeB.objects.create(balance=10, name='Vincent Law', cls="accounttypeB") accounttypeA.objects.create(balance=9.5, name='Re-l Mayer', cls="accounttypeA") for obj in account.objects.all(): obj.ext().addToBalance(1.0) print(obj.name, obj.cls)
but you MUST create models using accounttypeA.objects.create(...)
and accounttypeB.objects.create(...)
- or else this trick will not work.(https://docs.djangoproject.com/en/1.5/topics/db/models/#multi-table-inheritance)