我使用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 PlanSerializer(serializers.DocumentSerializer):
subplans = PlanSerializer(many=True, required=False)
class Meta:
model = Plan
但对Python来说不正确。所以我使用元类动态地添加subplans
字段:
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
如何将PlanSerializer
类设置为元类__new__
方法中的属性?
答案 0 :(得分:0)
您遇到的问题是当您尝试使用该行时
subplans = PlanSerializer(many=True, required=False)
当您尝试使用元类时,当您的PlanSerializerclass本身尚未定义时,行class_obj = globals()[name]
。 (在How is super() in Python 3 implemented?)检查我的答案
在元类中执行此操作的正确方法是首先调用超类的新类 - 它返回实际的类对象,然后调用该对象 - 其中包含:
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
但这不是必需的,并且可能仍然存在问题 - 因为当您仍处于元类的__new__
(或甚至__init__
)方法中时,并非所有类初始化都已完成。例如,如果__init__
本身的PlanSerializer
方法会使用super
,则该调用将失败 - super
只能在完全初始化类之后使用。< / p>
但是,您根本不需要元类 - 您可以简单地将subplans
属性设置为描述符 - 并且懒惰地检索属性。
class PlanSerializer(serializers.DocumentSerializer):
class Meta:
model = Plan
PlanSerializer.subplans = PlanSerializer(many=True, required=False)
我之所以说可能是因为如果Mongo在初始化类本身时需要设置属性,那么它将无法工作 - 如果是这种情况,你可以尝试使用描述符对象。描述符只是实现__get__
方法的对象,如下所示。这通常使用@property
装饰器完成,但这对于类级别属性不起作用,这是本案例所需要的。
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
类的调用的使用被延迟到实际使用时,而不是解析类主体的时间,它应该有效。