我正在尝试做一些元类hocus-pocus。我想要自己的元类
从ModelBase
继承,然后我想添加额外的逻辑
扩展其__new__
方法。不过我认为有一些东西
我使用MRO /继承顺序的方式很奇怪。
以下是基本情况:
from django.db.models import Model, ModelBase
class CustomMetaclass(ModelBase):
def __new__(cls, name, bases, attrs):
# As I am trying to extend `ModelBase`, I was expecting this
# call to `super` to give me the return value from here:
# https://github.com/django/django/blob/master/django/db/models/base.py#L300
# And that I would be able to access everyhing in `_meta` with
# `clsobj._meta`. But actually this object is
# `MyAbstractModel` and has no `_meta` property so I'm pretty
# sure `__new__` isn't being called on `ModelBase` at all at
# this point.
clsobj = super().__new__(cls, name, bases, attrs)
# Now, I want to have access to the `_meta` property setup by
# `ModelBase` so I can dispatch on the data in there. For
# example, let's do something with the field definitions.
for field in clsobj._meta.get_fields():
do_stuff_with_fields()
return clsobj
class MyAbstractModel(metaclass=CustomMetaclass):
"""This model is abstract because I only want the custom metaclass
logic to apply to those models of my choosing and I don't want to
be able to instantiate it directly. See the class definitions below.
"""
class Meta:
abstract = True
class MyModel(Model):
"""Regular model, will be derived from metaclass `ModelBase` as usual.
"""
pass
class MyCustomisedModel(MyAbstractModel):
"""This model should enjoy the logic defined by our extended `__new__` method.
"""
pass
__new__
ModelBase
CustomMetaClass
未被调用的任何想法
ModelBase
?如何以这种方式正确扩展FilteredDbSet
?我非常确定元类继承是可能的
但似乎我错过了一些东西......
答案 0 :(得分:0)
获取clsobj
_meta
属性的方法非常简单:
class CustomMetaclass(ModelBase):
def __new__(cls, name, bases, attrs):
bases = (Model,)
clsobj = super().__new__(cls, name, bases, attrs)
for field in clsobj._meta.get_fields():
do_stuff_with_fields()
return clsobj
我们可以使用MyAbstractModel(Model, metaclass=CustomMetaclass)
执行相同的操作。
但是,这里的最终成功仍然取决于我们打算在__new__
方法中开展的工作。如果我们想以某种方式反省并使用元编程来处理类的字段,我们需要注意我们正在尝试使用{strong> import 时的__new__
重写该类,从而(因为这是Django)app registry尚未就绪,如果出现某些条件(例如我们被禁止访问或使用反向关系),这可能会导致异常被引发。即使Model
作为基础传递到__new__
,也会发生这种情况。
我们可以通过使用以下对_get_fields
的非公开调用来解决其中一些问题(Django在某些地方自行调用):
class CustomMetaclass(ModelBase):
def __new__(cls, name, bases, attrs):
bases = (Model,)
clsobj = super().__new__(cls, name, bases, attrs)
for field in clsobj._meta._get_fields(reverse=False):
do_stuff_with_fields()
return clsobj
但是根据情景和我们想要实现的目标,我们可能仍会遇到问题;例如,我们无法使用我们的元类访问任何反向关系。所以仍然没有好处。
为了克服这一限制,我们必须利用app注册表中的信号,使我们的课程充满活力,因为我们希望他们能够完全访问_meta.get_fields
。
查看此票证:https://code.djangoproject.com/ticket/24231
主要内容是:" Django模型类不允许您在准备好的应用程序注册表的上下文之外使用。"