如何做类似 Django 模型的元类技巧

Posted

技术标签:

【中文标题】如何做类似 Django 模型的元类技巧【英文标题】:How to do Django-models-like metaclass trick 【发布时间】:2015-03-15 08:46:51 【问题描述】:

我正在为我的学习项目制作类似于 ORM 的 Django,因为我们不允许使用现有的 ORM(如果你想使用一个,你必须自己编写代码)并且只是为了教育自己,我认为是同一种像 Django 中的 ORM 会很好。

在 ORM 中,我不想以与在 Django 中实现的相同样式来制作模型定义。即。

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

Django 使用元类,在我的项目中我也在使用,但我对元类构造 classes 而不是实例的事​​实有疑问,因此所有属性都是类属性并在所有实例之间共享。

这是我尝试过的通用示例,但由于我之前所说的,它不起作用:

def getmethod(attrname):
    def _getmethod(self):
        return getattr(self, "__"+attrname).get()
    return _getmethod

def setmethod(attrname):
    def _setmethod(self, value):
        return getattr(self, "__"+attrname).set(value)
    return _setmethod

class Metaclass(type):
    def __new__(cls, name, based, attrs):
        ndict = 
        for attr in attrs:
            if isinstance(attrs[attr], Field):
                ndict['__'+attr] = attrs[attr]
                ndict[attr] = property(getmethod(attr), setmethod(attr))
        return super(Metaclass, cls).__new__(cls, name, based, ndict)


class Field:
    def __init__(self):
        self.value = 0;

    def set(self, value):
        self.value = value

    def get(self):
        return self.value

class Mainclass:
    __metaclass__ = Metaclass

class Childclass(Mainclass):
    attr1 = Field()
    attr2 = Field()


a = Childclass()
print "a, should be 0:", a.attr1
a.attr1 = "test"
print "a, should be test:", a.attr1

b = Childclass()

print "b, should be 0:", b.attr1

我试图从 Django 的源代码中查找,但它太复杂了,我无法理解,而且“魔法”似乎隐藏在某个地方。

问题很简单,Django如何在非常简单的例子中做到这一点?

【问题讨论】:

【参考方案1】:

只要检查正确的代码,答案其实很简单。 Django 使用的元类将所有字段添加到<model>._meta.fields(嗯,有点),但从实际类中删除了字段属性。唯一的例外是RelatedField 子类,在这种情况下添加了一个对象描述符(类似于属性 - 实际上,属性是一个对象描述符,只是具有本机实现)。

然后,在模型的__init__ 方法中,代码遍历所有字段,并在*args**kwargs 中设置提供的值,或者在实例上设置默认值时间>。

在您的示例中,这意味着类Person 永远不会有名为first_namelast_name 的属性,但是这两个字段都存储在Person._meta.fields 中。但是,Person 的实例将始终具有名为 first_namelast_name 的属性,即使它们没有作为参数提供。

【讨论】:

以上是关于如何做类似 Django 模型的元类技巧的主要内容,如果未能解决你的问题,请参考以下文章

django 模型元类的标准文档字符串是啥?

django:为啥我们在 modelSerializer 中使用嵌套的元类?

Django:调用元类库时出错

模型元类与模型形式元类有何不同?

Django:从带有元的抽象类的多重继承

TypeError:python中的元类冲突