到目前为止,关于SO的所有其他答案都以完全相同的方式回答:构造你的元类然后继承那些元类的“连接”版本,即
class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass
但我不知道这些人住在哪个世界,他们在哪里构建自己的元类!显然,一个人会使用其他库中的类,除非你对元编程有一个完美的处理,你怎么知道你是否可以覆盖一个类的元类? (显然我还没有处理它们。)
我的问题是:
class InterfaceToTransactions(ABC):
def account(self):
return None
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...
当然这给了我错误:“元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类” 我已经尝试了上面给出的解决方案的许多变体,以下不起作用,给出了相同的错误。
class InterfaceToTransactionsIntermediaryMeta(type(PolymorphicModel), type(InterfaceToTransactions)):
pass
class Category(PolymorphicModel, InterfaceToTransactions):
__metaclass__ = InterfaceToTransactionsIntermediaryMeta
...
也没有把任何东西放在Meta函数中。我已经阅读了关于这个主题的每一个其他问题,请不要简单地将其标记为重复。
-------------------在接受解决方案后的1/8/18编辑-------
奇怪的是,如果我尝试使用这个新配置(我接受的那个)进行移植,它会再次开始给出元类错误,但它在运行时仍然有效。如果我注释掉元类部分然后makemigrations并迁移,它会成功完成,但是每次迁移后我都要把它放回去。
答案 0 :(得分:2)
如果您使用的是Python 3,则会尝试错误地使用派生的元类。
既然你得到了同样的错误",而不是其他可能的,更微妙的错误,我说这就是发生的事情。
尝试更改为:
class IntermediaryMeta(type(InterfaceToTransactions), type(PolymorphicModel)):
pass
class Category(PolymorphicModel, InterfaceToTransactions, metaclass=IntermediaryMeta):
...
(至少ABCMeta类保证使用super
协同工作,这足以将classe首先放在基础上)
元组)
如果这会产生新的和改进的错误,这意味着由于其中一个动机,这些类中的一个或两个都无法正确协作。然后,要走的路是强制你的依赖ABCMeta的继承树不要这样做,因为它的作用几乎是一种语言的美学,其他一切都是为了同意成年人"像Python一样。
不幸的是,通往这种方式的方法是使用各种蛮力方法,从安全"重写一切"猴子修补ABCMeta和抽象方法的地方是" InterfaceToTransactions"被定义为什么都不做。
如果您需要到达那里并需要帮助,请发布另一个问题。
抱歉 - 这实际上是使用元类的主要缺点。
答案 1 :(得分:0)
除非django-polymorphic决定继承abc.ABC,否则这将很难实现。一个好的解决方案是“手动”创建您的界面。例如:
class InterfaceToTransactions:
def account(self):
raise NotImplementedError("Account method must be implemented.")
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...