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
,而我想根据实例获得dog
或cat
。我在Python多态世界中没有理解什么,我该如何解决它?
您可以使用点符号(如属性)访问狗和猫对象。查询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
然后你遇到了一个奇怪的情况,Django对象既可以是'Cat' *也可以是'Dog',但是却无法用Python来表示它。 –
呃..是的,你是对的 –
我知道这是针织挑剔,但是:不应该在动物类中定义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()
然后,你可以忘记任何动物的子类。它适用于我,希望这有助于。
做'query [0] .dog.ClassType'或'query [0] .cat.ClassType' –
谢谢 - 这是我没有意识到的选项。然而,这是否意味着我需要先验地知道子类,或者至少遍历所有可能的子类来查看哪些子类存在?有没有更好的办法 ? – e7mac
为什么当你的课程已经从它继承时,你需要与动物建立一对一的关系? –