Python多态对象调用基类方法而不是子类方法

问题描述:

我在Django中有以下模型。我有理由不让Animal成为抽象基类。Python多态对象调用基类方法而不是子类方法

class Animal(models.Model): 
    sound = "none" 
    def ClassType(self): 
     return 'animal' 

class Cat(Animal): 
    animal_id = models.OneToOneField(Animal,parent_link=True) 
    sound = "meow" 
    def ClassType(self): 
     return 'cat' 

class Dog(Animal): 
    animal_id = models.OneToOneField(Animal,parent_link=True) 
    sound = "bow" 
    def ClassType(self): 
     return 'dog' 

我查询了一组动物为

query = Animal.objects.all()

结果必然是唯一的狗和猫的列表。然而,在调用

query[0].ClassType

我只得到animal。 “查询”中的所有对象都给我animal,而我想根据实例获得dogcat。我在Python多态世界中没有理解什么,我该如何解决它?

+0

做'query [0] .dog.ClassType'或'query [0] .cat.ClassType' –

+0

谢谢 - 这是我没有意识到的选项。然而,这是否意味着我需要先验地知道子类,或者至少遍历所有可能的子类来查看哪些子类存在?有没有更好的办法 ? – e7mac

+0

为什么当你的课程已经从它继承时,你需要与动物建立一对一的关系? –

您可以使用点符号(如属性)访问狗和猫对象。查询Animal.objects.all()将返回将包括所有猫和狗的所有动物。

qs = Animal.objects.all() 
for animal in qs: 
    try: 
     obj = animal.cat 
     # its a cat 
    except AttrbuteError: 
     # its a dog 
     obj = animal.dog 

正如你看到有只是一个小故障识别哪一个是狗,哪一个是猫,一个很好的办法会在你的动物模型设置临时属性:

class Animal(models.Model): 
    sound = "none" 

    def is_cat(self): 
     if not hasattr(self, '_is_cat'): 
      self._is_cat = Cat.objects.filter(animal_id=self).exists() 
     return self._is_cat 

现在你只需简单地做:

qs = Animal.objects.all() 
for animal in qs: 
    if animal.is_cat(): 
     # this is a cat 
    else: 
     # dog 
+0

然后你遇到了一个奇怪的情况,Django对象既可以是'Cat' *也可以是'Dog',但是却无法用Python来表示它。 –

+0

呃..是的,你是对的 –

+0

我知道这是针织挑剔,但是:不应该在动物类中定义is_cat()。相反,你应该使用:“if isinstance(animal,Cat):”而不是“if animal.is_cat():”。原因是,is_cat()将被继承动物的所有其他非Cat类继承,而不仅仅是猫。这意味着在大多数情况下可能不会使用另外一种方法。 –

制作ClassType的方法相反的,你应该让一个实际的领域,存储对象的类型,当你保存。否则,当你发现,当你查询动物时,你只会得到动物,而不是亚型。

这个问题是老了,但我跌倒在同样的问题,所以这里是我的解决方案,这:

我用django_polymorphic应用程序,它是有几个原因非常有用,但它相应提供的属性模型实例及其名称,您可以使用它来解决您的问题。

所以,你可以改变你的基类如下所示:

class Animal(PolymorphicModel): 
    sound = "none" 

    def ClassType(self): 
     polymorphic_attr_name = self.name.lower().replace(" ", "") # Get the name of the attribute that points to the instance 
     if polymorphic_attr_name == 'animal': 
      return 'animal' 
     instance = getattr(self, polymorphic_attr_name) 
     instance.ClassType() 

然后,你可以忘记任何动物的子类。它适用于我,希望这有助于。