14

I have a following model and abstract base class

import abc
from django.db import models


class AbstractBase():
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def my_method(self):
        return


class MyModel(models.Model, AbstractBase):
    @abc.abstractmethod
    def my_method(self):
        return 1

But I am getting the following error.

metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I think the problem here is (As it is described here http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/) that two base class has two different metaclasses so python cannot decide which metaclass to use for child object.

In order to solve this I removed multiple inheritence and use following register method to register child class

abc.register(Child)

But I did not really like this approach since it looks like monkey patching.

Is there another way to solve this problem?

I try to assign Model metaclass to Child explicitly but it did not work. I am not looking for a way to solve it by writing code. I think this must be solved by changing my class structure.

yilmazhuseyin
  • 6,442
  • 4
  • 34
  • 38
  • I think you're going to have to create a new metaclass that does both django's and abc's things, probably by calling their respective metaclasses in order, maybe using inheritance. – cha0site Jan 04 '12 at 08:14
  • There is nothing hackish about using the abs.register method - it is designed exactly for these cases. BTW, Python way o f thinking things is done so you rarely should _need_ interfaces and such - maybe you are too constrained by the way things are done in static languages? – jsbueno Jan 04 '12 at 10:12
  • @jsbueno - You might be right, but I will need to implement interface functionality in some way. Here is an example implantation- https://gist.github.com/1559689 . Is there a better way to implement this functionality, in python? – yilmazhuseyin Jan 04 '12 at 11:41

1 Answers1

2

Apart from creating a new metaclass that inherits from both ABCMeta and ModelBase, or making ABCMeta inherit from ModelBase, there isn't much you can do.

However, possibly a different registration pattern might be appropriate? Maybe something like contrib.admin.autodiscover? Or a class decorator? Or a loop at the bottom of the .py file which calls register on the appropriate classes (ex, for var in globals().values(): if isinstance(var, type) and issubclass(var, AbastractBase): register(var))?

Edit: D'oh. I'd assumed that ABCMeta was an example, not ABCMeta. That's what I get for browsing StackOverflow on too little sleep.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • 1
    My conclusion about this is If I am using abc's as an interface, I should use abc.register. I really think that there should be a better way to implement an interface(http://www.python.org/dev/peps/pep-0245/). Without them oo features of python seems very weak to me. – yilmazhuseyin Jan 04 '12 at 09:09
  • 3
    If you feel that this "makes Python's OO weak", then I might humbly suggest that your understanding of the "requirements for strong OO" differ drastically from those of Python's designers (or that you accidentally typed "oo" when you meant to type "static type checking"?) – David Wolever Jan 04 '12 at 16:40