使用ABC,PolymorphicModel,django-models给出了元类冲突

mas*_*imp 6 python django metaclass abc django-polymorphic

到目前为止,关于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
Run Code Online (Sandbox Code Playgroud)

但我不知道这些人住在哪个世界,他们在哪里构建自己的元类!显然,一个人会使用其他库中的类,除非你对元编程有一个完美的处理,你怎么知道你是否可以覆盖一个类的元类?(显然我还没有处理它们).

我的问题是:

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
    ...
Run Code Online (Sandbox Code Playgroud)

这当然给了我错误:"元类冲突:派生类的元类必须是其所有基础的元类的(非严格)子类" 我已经尝试了上面给出的解决方案的许多变体,以下是不工作,给出同样的错误.

class InterfaceToTransactionsIntermediaryMeta(type(PolymorphicModel), type(InterfaceToTransactions)):
pass

class Category(PolymorphicModel, InterfaceToTransactions):
    __metaclass__ = InterfaceToTransactionsIntermediaryMeta
    ...
Run Code Online (Sandbox Code Playgroud)

也没有把任何东西放在Meta函数中.我已经阅读了关于这个主题的每一个其他问题,请不要简单地将其标记为重复.

-------------------在接受解决方案后的1/8/18编辑-------

奇怪的是,如果我尝试使用这个新配置(我接受的那个)进行迁移,它会再次开始给出元类错误,但它仍然可以在运行时运行.如果我注释掉元类部件然后makemigrations并迁移,它会成功完成,但是每次迁移后我都必须把它放回去.

jsb*_*eno 2

如果您使用的是 Python 3,则您正在尝试错误地使用派生元类。

既然你得到了“同样的错误”,而不是其他可能的、更微妙的错误,我想说这就是正在发生的事情。

尝试更改为:

class IntermediaryMeta(type(InterfaceToTransactions), type(PolymorphicModel)):
    pass

class Category(PolymorphicModel, InterfaceToTransactions, metaclass=IntermediaryMeta):
    ...
Run Code Online (Sandbox Code Playgroud)

(至少 ABCMeta 类保证可以使用 协同工作super,这足以将它的类放在基础上)元组)

如果这会产生新的和改进的错误,则意味着这些类中的一个或两个由于多种动机之一而无法真正正常协作。然后,要采取的方法是强制依赖于 ABCMeta 的继承树不要这样做,因为在像 Python 这样的语言中,其他一切都是为了“同意的成年人”而设计的,它的作用几乎是美学的。

不幸的是,实现这一目标的方法是使用各种暴力方法,从安全的“重写所有内容”到猴子修补 ABCMeta 和抽象方法,其中“InterfaceToTransactions”被定义为简单地不执行任何操作。

如果您需要到达那里并需要一些帮助,请发布另一个问题。

抱歉 - 这实际上是使用元类的主要缺点。