0

In Django, I'd like to implement __getitem__ on a class level (so in the below example, I want to do Alpha['a']). I've found that I need a metaclass for this: just like it this needs to be implemented on a class to make it accessible on the instance, it must be implemented on a metaclass to use it on class level, as I understand it.

class AlphaMeta(type):

    a = 7

    def __getitem__(self, key):
        return getattr(self, key)

class Alpha(models.Model):

    value = models.CharField(max_length = 64, default = '')

    __metaclass__ = AlphaMeta

print Alpha['a']

The problem is that I get the error below. It works fine if Alpha is a normal new-style class (class Alpha(object)), but for a more complex base it needs more. However, I don't unstand what it wants from me, as I don't understand what the metaclasses of all it's bases are.

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

I'm very new to metaclasses; any hints are greatly appreciated!

EDIT: model fields go in Alpha rather than AlphaMeta

Manuel Allenspach
  • 12,467
  • 14
  • 54
  • 76
Mark
  • 18,730
  • 7
  • 107
  • 130

1 Answers1

1

I would really suggest avoiding messing with the metaclass of models as you can easily run into some weird issues that are hard to debug. Anyway, if you still want to do this, the error message tells you what you need to do.

AlphaMeta needs to be a subclass of the metaclass of models.Model, which is django.db.models.base.ModelBase. So try

from django.db.models.base import ModelBase

class AlphaMeta(ModelBase):
    …

You probably also want to call the superclass implementation in the case of a KeyError.

Michael Mior
  • 28,107
  • 9
  • 89
  • 113
  • Thanks for the answer! I might not go down that road then, thanks for the warning. Anyway it works. I was afraid it might make a table for the meta class but it doesn't so all is wonderful. – Mark Dec 28 '12 at 03:53
  • Why not just add `a = 7` to `Alpha` and then use `Alpha.a`? – Michael Mior Dec 28 '12 at 05:04
  • It's a simplified example :) I do `item.value for item in Model` a little more conveniently, for example. But indeed there is nothing that is completely impossible the conventional way. – Mark Dec 28 '12 at 23:37
  • 1
    Fair enough :) You may want to post another question which explains the problem you're trying to solve. – Michael Mior Dec 29 '12 at 01:02