在Django模型中选择基于字段值的方法

时间:2015-08-29 08:40:33

标签: python django python-3.x polymorphism

概括地说,我有一个Django模型,我希望实例根据其中一个字段的值具有不同的行为:

ANIMAL_TYPES = ('cow', 'african swallow', 'dog')
ANIMAL_TYPE_CHOICES = tuple(enumerate(ANIMALS, start=1))

class Animal(models.Model):
    animal_type = models.PositiveIntegerField(choices=ANIMAL_TYPE_CHOICES)
    # ... other model fields

    def speak_cow(self):
        return 'moo'

    def speak_african_swallow(self):
        return 'squawk'

    def speak_dog(self):
        return 'woof'

    choose_speak = {i: getattr(Animal,'speak_{}'.format(
             name.replace(' ', '_'))) for (i, name) in ANIMAL_TYPE_CHOICES}

    def speak(self):
        return Animal.speak[self.animal_type](self)

目标是能够在speak()的实例上调用Animal,并让班级选择正确的speak方法。 (要明确的是:speak方法比返回字符串要多得多。)

这不起作用:Animal不是由我在choose_speak词典理解中使用它时定义的。choose_speak = [None, speak_cow, speak_african_swallow, speak_dog] 。目前,我的解决方法是使用

speak_sheep

但有没有办法自动生成我想要的内容,所以我不必手动添加我定义的任何新方法(例如val mediator = DistributedPubSubExtension(system).mediator val chatMember1 = TestProbe() mediator ! Subscribe(topic, chatMember1.ref) //... Call the publisher to publish message chatMember1.expectMsg(ChatMessage(UserId, message)) )?

2 个答案:

答案 0 :(得分:2)

您需要的是getattr

def speak(self):
    method_name = choose_speak[self.animal_type]
    method = getattr(self, method_name)
    return method()

但是我是你,我现在只在if ... else使用speak,因为它更加简单明了。

答案 1 :(得分:2)

您还可以定义包含动物所有声音的列表......即

 ANIMAL_SOUNDS = ['moo', 'squawk'..]

这样你就不必定义新方法了。 使用它说:

def speak(self):
    return ANIMAL_SOUNDS[self.animal_type]

修改

只是为了它,我玩了一下,并在纯python中提出了这个代码,可能接近你想要的:

ANIMAL_TYPES = ('cow', 'african swallow', 'dog')
ANIMAL_TYPE_CHOICES = tuple(enumerate(ANIMAL_TYPES, start=1))

class Animal(object):

    def __init__(self, *args, **kwargs):
        self.choose_speak = {i: getattr(self, 'speak_{}'.format(
            name.replace(' ', '_'))) for (i, name) in ANIMAL_TYPE_CHOICES}

    animal_type = 1

    def speak_cow(self):
        return 'moo'

    def speak_african_swallow(self):
        return 'squawk'

    def speak_dog(self):
        return 'woof'

    def speak(self):
        return self.choose_speak[self.animal_type]()

animal = Animal()
animal.speak()

注意:覆盖模型的__init__不是Django最佳实践,如here所示: