问题
How do you override a model's metaclass in Django 1.5? I was overriding the metaclass on some models inheriting from an abstract model so I could set appropriate choices. e.g.
class BaseModel(models.Model):
field_with_choices = models.CharField(max_length=100)
class Meta:
abstract = True
class MyModelMetaClass(BaseModel.__metaclass__):
def __new__(cls, *args, **kwargs):
new_class = super(MyModelMetaClass, cls).__new__(cls, *args, **kwargs)
field = new_class._meta.get_field('field_with_choices')
choices = field._choices = []
choices.extend(get_choices())
return new_class
class MyModel(BaseModel):
__metaclass__ = MyModelMetaClass
However, when I upgraded to Django 1.5, I now get the error:
AttributeError: type object 'BaseModel' has no attribute '__metaclass__'
How do you override a model's metaclass in 1.5, or otherwise dynamically set field attributes in model subclasses?
回答1:
You can use the built-in
function type
like this:
class MyModelMetaClass(type(BaseModel)):
def __new__(cls, *args, **kwargs):
new_class = super(MyModelMetaClass, cls).__new__(cls, *args, **kwargs)
field = new_class._meta.get_field('field_with_choices')
choices = field._choices = []
choices.extend(get_choices())
return new_class
Although I see that type(ModelBase) is type
so you basically could inherit from type
or maybe from Model.__metaclass__
which is in turn ModelBase
so ModelBase
is the top of the Model metaclass architecture (before type
of course :D ).
Hope it helps!
回答2:
If I understand correctly, django 1.5 is using six for compatibility management. According to the docs, the proper way would be the following:
from six import with_metaclass
class Meta(type):
pass
class Base(object):
pass
class MyClass(with_metaclass(Meta, Base)):
pass
来源:https://stackoverflow.com/questions/16552812/missing-metaclass-in-django-1-5