访问Python Django中的子方法

时间:2015-03-03 00:39:48

标签: python django

我有一个真实的案例,可以使用像Java中的多态来解决我们可以在哪里创建属于同一类型的对象列表。但是,每个对象可能具有覆盖或额外字段。

class Animal(models.Model):
    name = models.CharField(max_length=30)

    def speak(self):
        return "I am an animal"


class Cat(Animal):

    def speak(self):
        """ OVERRIDE """
        return "MEAOO"


class Dog(Animal):

    def speak(self):
        """ OVERRIDE """
        return "WOOOOF"

我现在需要的是获得所有动物,但让每只动物使用它的说话方法。我无法如下所示。

>>> c = Cat(name="MyCAT")
>>> c.save()
>>> d = Dog(name="MyDOG")
>>> d.save()
>>> animals = Animal.objects.all()
>>> animals
[<Animal: Animal object>, <Animal: Animal object>]
>>> for a in animals:
...     a.speak()
... 
'I am an animal'
'I am an animal'
>>> 

对我而言,输出应该如下所示

'MEAOO'
'WOOOOF'

有没有在Django做类似的事情?

1 个答案:

答案 0 :(得分:1)

我最近遇到了这个问题。我有几个子类,而且所有子类都略有不同&#34;说&#34;方法

我基本上做的是在我的父类中创建一个downcast函数,它检查相关的子类实例。这是有效的,因为当您将模型子类化时,django通过OneToOneField链接它们,这可以通过两种方式遍历:

class Animal(models.Model):
    name = models.CharField(max_length=30)
    _downcast = None
    # to store the subclass instance, so that
    # subsequent calls don't hit the database

    def speak(self):
        return "I am an animal"

    def downcast(self):
        if self._downcast is None:
            if hasattr(self, 'cat'):
                self._downcast = self.cat
            elif hasattr(self, 'dog'):
                self._downcast = self.dog

        return self._downcast


class Cat(Animal):
    def speak(self):
        """ OVERRIDE """
        return "MEAOO"


class Dog(Animal):
    def speak(self):
        """ OVERRIDE """
        return "WOOOOF"

基本上,你只是...有点......去找它,并问你的数据库这个Animal是否确实有一个相关的Cat行:

>>> a = Animal.objects.all().first() #let's assume this is a cat
>>> a.speak()
I am an animal
>>> a.downcast().speak()
MEAOO

当然,这会查询数据库,因此性能可能会受到影响。考虑一下您自己的场景并运行一些测试,看看这是否适合您。