在Django中重写Model类的__getattribute__
在Django中,我想创建一个模型,这个模型的一个实例可以从另一个同样的实例中继承值,就像父类和子类的关系一样。我在这个模型里创建了一个叫做parent的字段,它是一个可选的自引用外键。接着,我想重写__getattribute__方法,代码如下:
def __getattribute__(self, name):
if models.Model.__getattribute__(self, 'parent') is None:
return models.Model.__getattribute__(self, name)
elif models.Model.__getattribute__(self, name) is not None:
return models.Model.__getattribute__(self, name)
else:
return parent.__getattribute__(name)
这段代码导致了无限递归,因为模型类的__get__方法调用了内置的getattr方法,而这个方法的第一个参数是实例本身。
有没有其他方法可以实现我想做的事情呢?
3 个回答
1
我想 overriding __getattribute__
或 __getattr__
可能会影响性能。可能有更好的方法来解决这个问题:
- 在模型实例初始化的时候,如果一个可继承的字段是空的,而对应的父类字段不是空的,就用
setattr(self, field_name, getattr(self.parent, field_name))
把父类的值赋给这个字段。 - 记录模型实例字段的变化。
- 在保存这个实例之前,把那些之前被覆盖但没有改变的字段设置为
None
。
我正在为此开发一个Django应用:https://github.com/Altaisoft/django-inheritance
2
你需要让父类的属性覆盖掉自己的属性吗?如果不需要的话,最好重写 __getattr__()
方法,而不是 __getattribute__()
方法。因为当实例本身有同名的属性时,__getattribute__()
方法是不会被调用的。
def __getattr__(self, name):
return getattr(self.parent, name)
3
这样做会遇到很多困难。
请考虑重新使用 __getattribute__
,而是用普通的属性来处理这个问题。
我觉得简单的“获取器”(getter)配合属性名称就能满足你的需求,而且不会涉及到复杂的魔法操作。
是的,你可能会有几个相似的字段,但我认为简单明了的属性更适合Django的ORM(对象关系映射)。