Django multi-table inheritance, how to know which is the child class of a model?

前端 未结 4 2131
梦毁少年i
梦毁少年i 2021-02-19 03:13

I\'m having a problem with multi-table inheritance in django.

Let’s make an example with bank accounts.

class account(models.Model):
    name = models……         


        
相关标签:
4条回答
  • 2021-02-19 03:49

    You can use hasattr() method like:

    if hasattr(account, 'accounttypea'):
       account.accounttypea.<somefield> = <some value>
       do something here....
    
    elif hasattr(account, 'accounttypeb'):
       account.accounttypeb.<somefield> = <some value>
       do something here...
    

    It's not so DRY but works. :)

    0 讨论(0)
  • 2021-02-19 03:59

    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 += value
    
    class accounttypeB(account):
        balance = models.int…. # NOTE this
    
    0 讨论(0)
  • 2021-02-19 04:06

    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 += value
    
    
    class accounttypeB(account):
        balance = models.int…. # NOTE this
    
        def addToBalance(self, value):
            value = do_some_thing_with_value(value) # NOTE this
            self.balance += value
    
    # example
    accounttypeB.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)

    0 讨论(0)
  • 2021-02-19 04:07

    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 typeA
    except accounttypeA.DoesNotExist:
        # acc should be typeB if account only has typeA and typeB subclasses
    
    try:
        typeB = acc.accounttypeB
        # acc is typeB
    except accounttypeB.DoesNotExist:
        # acc should be typeA if account only has typeA and typeB subclasses
    
    0 讨论(0)
提交回复
热议问题