繁体   English   中英

Django多表继承,如何知道模型的子类?

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

我在Django中遇到多表继承问题。

让我们以银行帐户为例。

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

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

现在,我想为帐户类型添加一个值,但是我所拥有的只是一个帐户对象,例如acc = account.object.get(pk = 29)。 那么,acc的孩子是谁?

Django会在accounttypeA和accounttypeB中自动创建一个account_ptr_id字段。 因此,我的解决方案是:

child_class_list = ['accounttypeA', 'accounttypeB']

for cl in child_class_list:
    try:
        exec(“child = ” + str(cl) + “.objects.select_for_update().get(account_ptr_id=” +              str(acc.id) + “)”)
        logger.debug(“Child found and ready to use.”)
        return child
    except ObjectDoesNotExist:
        logger.debug(“Object does not exist, moving on…”)

也许这是一个绘图板问题! :)

我希望我的例子很清楚。 谢谢

据我所知,没有Django内置方法可以做到这一点。

但是,给定acc=account.object.get(pk=29) ,您可以使用:

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

我的解决方案是基于

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

Django在类account添加了两个字段: accounttypeaaccounttypeb 如果您具有带有pk = 42的accounttypeB对象,则可以像这样从父级访问:

account.objects.get(pk=42).accounttypeb
>>> <accounttypeB instance>

您可以将CharField添加到具有每个孩子的实际子类型的父模型,然后使用getattr (如果有很多子模型(它可能比很多try .. except xxx.DoesNotExist更好, try .. except xxx.DoesNotExisttry .. except xxx.DoesNotExist ))。

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)

但您必须使用accounttypeA.objects.create(...)accounttypeB.objects.create(...)创建模型-否则,此技巧将不起作用。 https://docs.djangoproject.com/en/1.5/topics/db/models/#multi-table-inheritance

您可以使用hasattr()方法,例如:

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

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

它不是那么干,但可以。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM