Django 继承:如何为所有子类定义一个方法?
我有一个模型
BaseModel
还有几个它的子类
ChildModelA(BaseModel), ChildModelB(BaseModel), ...
我使用的是多表继承。将来我计划会有几十个子类模型。
所有的子类都有某种实现的方法
do_something()
我该如何从一个BaseModel实例中调用do_somthing?
这里有一个几乎相同的问题(没有解决方案):
http://peterbraden.co.uk/article/django-inheritance
还有一个更简单的问题:我该如何将BaseModel实例转换为它的某个子类实例,而不需要检查所有可能的子类?
3 个回答
我同意Andrew的看法。在我们的一些网站上,有一个类支持很多方法(但没有字段,因为这是在重构之前的事情),这些方法对我们大多数内容类都是通用的,但并不是所有的内容类都有。这些方法使用了hasattr来避免一些方法不适用的情况。
这意味着我们大多数的类都是这样定义的:
class Foo(models.Model, OurKitchenSinkClass):
基本上这就像是一种MixIn的方式。效果很好,维护起来也很简单。
你会不会一直在使用基类的实例,还是说你总是使用子类的实例?如果是后者,那就直接调用方法吧,即使你手上有基类的引用,因为这个对象本身就是子类的类型。
由于Python支持鸭子类型,这意味着你的方法调用会正确绑定,因为子类的实例确实有这个方法。
一种Python编程风格,它通过检查对象的方法或属性来判断对象的类型,而不是通过与某个类型对象的明确关系来判断(“如果它看起来像鸭子,叫声也像鸭子,那它一定是鸭子。”)。这种风格强调接口而不是具体类型,设计良好的代码通过允许多态替换来提高灵活性。鸭子类型避免使用type()或isinstance()进行类型检查。不过,鸭子类型可以与抽象基类结合使用。通常,它会使用hasattr()测试或EAFP编程。
需要注意的是,EAFP代表比起请求许可,更容易请求原谅:
比起请求许可,更容易请求原谅。这种常见的Python编码风格假设存在有效的键或属性,如果假设错误就捕获异常。这种干净快速的风格特点是有很多try和except语句。这种技术与许多其他语言(如C语言)常见的LBYL风格形成对比。
如果你想避免检查所有可能的子类,我想到的唯一办法就是在基类中定义一个字段,用来存储与子类相关的类名。你的基类可以有一个像这样的函数:
def resolve(self):
module, cls_name = self.class_name.rsplit(".",1)
module = import_module(module)
cls = getattr(module, cls_name)
return cls.objects.get(pk=self.pk)
这个答案让我不太满意,我也希望能看到更好的解决方案,因为我很快就会遇到类似的问题。