在Python元类中添加带有类的动态属性
我使用mongoengine和django rest框架。我的模型:在Python元类中添加带有类的动态属性,python,django-rest-framework,mongoengine,metaclass,Python,Django Rest Framework,Mongoengine,Metaclass,我使用mongoengine和django rest框架。我的模型: import mongoengine as mongo class Plan(mongo.Document): slug = mongo.StringField(max_length=255, primary_key=True) subplans = mongo.ListField(mongo.EmbeddedDocumentField('self')) 我需要的序列化程序如下所示: class PlanSe
import mongoengine as mongo
class Plan(mongo.Document):
slug = mongo.StringField(max_length=255, primary_key=True)
subplans = mongo.ListField(mongo.EmbeddedDocumentField('self'))
我需要的序列化程序如下所示:
class PlanSerializer(serializers.DocumentSerializer):
subplans = PlanSerializer(many=True, required=False)
class Meta:
model = Plan
但这对于Python来说是不正确的。因此,我使用元类动态添加子计划字段:
class AddSubplanAttrMetaclass(type):
def __new__(cls, name, bases, dct):
# this code is incorrect because PlanSerializer not in globals
class_obj = globals()[name]
dct['subplans'] = class_obj(many=True, required=False)
return super(AddSubplanAttrMetaclass, cls).__new__(cls, name, bases, dct)
class PlanSerializer(serializers.DocumentSerializer, metaclass=AddSubplanAttrMetaclass):
class Meta:
model = Plan
如何在元类的\uuuuu new\uuuuuu
方法中将PlanSerializer
类设置为属性 您遇到的问题是,当您尝试使用
subplans=PlanSerializer(many=True,required=False)
当尝试使用元类时,行class\u obj=globals()。(请查看我的答案)
在元类中实现这一点的正确方法是首先调用超类的新对象,即返回实际的类对象,然后调用该对象:
class AddSubplanAttrMetaclass(type):
def __new__(metacls, name, bases, dct):
# this code is incorrect because PlanSerializer not in globals
class_obj = super(AddSubplanAttrMetaclass, cls).__new__(metacls, name, bases, dct)
class_obj.subplans = class_obj(many=True, required=False)
return class_obj
但这两种方法都不是必需的,而且可能仍然存在问题,因为当您仍然在元类的\uuuuu new\uuuuu
(甚至\uuuu init\uuuu
)方法中时,并不是所有的类初始化都完成了。例如,如果PlanSerializer
本身的\uuuuu init\uuuu
方法将使用super
,则该调用将失败-super
只能在类完全初始化后使用
但是,您根本不需要元类,您可以简单地将子计划
属性设置为描述符,然后惰性地检索该属性
class PlanSerializer(serializers.DocumentSerializer):
class Meta:
model = Plan
PlanSerializer.subplans = PlanSerializer(many=True, required=False)
我之所以这么说,可能是因为如果Mongo在初始化类本身时需要设置属性,那么这将不起作用——如果是这样,您可以尝试使用描述符对象。描述符只是一个实现\uuuu get\uuuu
方法的对象,如下所示。这通常是通过@属性
装饰器来完成的,但这对于类级属性不起作用,在本例中需要这些属性
class PlanSerializer(serializers.DocumentSerializer):
class Subplans(object):
serializer = None
def __get__(self, instance, owner):
if not self.serializer:
self.serializer = PlanSerializer(many=True, required=False)
return self.serializer
subplans = Subplans()
class Meta:
model = Plan
这样,调用子计划类的使用将延迟到实际使用时,而不是解析类主体的时间,并且它应该可以工作。您遇到的问题是,当您尝试使用
subplans=PlanSerializer(many=True,required=False)
当尝试使用元类时,行class\u obj=globals()。(请查看我的答案)
在元类中实现这一点的正确方法是首先调用超类的新对象,即返回实际的类对象,然后调用该对象:
class AddSubplanAttrMetaclass(type):
def __new__(metacls, name, bases, dct):
# this code is incorrect because PlanSerializer not in globals
class_obj = super(AddSubplanAttrMetaclass, cls).__new__(metacls, name, bases, dct)
class_obj.subplans = class_obj(many=True, required=False)
return class_obj
但这两种方法都不是必需的,而且可能仍然存在问题,因为当您仍然在元类的\uuuuu new\uuuuu
(甚至\uuuu init\uuuu
)方法中时,并不是所有的类初始化都完成了。例如,如果PlanSerializer
本身的\uuuuu init\uuuu
方法将使用super
,则该调用将失败-super
只能在类完全初始化后使用
但是,您根本不需要元类,您可以简单地将子计划
属性设置为描述符,然后惰性地检索该属性
class PlanSerializer(serializers.DocumentSerializer):
class Meta:
model = Plan
PlanSerializer.subplans = PlanSerializer(many=True, required=False)
我之所以这么说,可能是因为如果Mongo在初始化类本身时需要设置属性,那么这将不起作用——如果是这样,您可以尝试使用描述符对象。描述符只是一个实现\uuuu get\uuuu
方法的对象,如下所示。这通常是通过@属性
装饰器来完成的,但这对于类级属性不起作用,在本例中需要这些属性
class PlanSerializer(serializers.DocumentSerializer):
class Subplans(object):
serializer = None
def __get__(self, instance, owner):
if not self.serializer:
self.serializer = PlanSerializer(many=True, required=False)
return self.serializer
subplans = Subplans()
class Meta:
model = Plan
通过这种方式,对子计划
类的调用的使用被延迟到实际使用时,而不是解析类主体的时间,并且应该可以正常工作