Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python元类中添加带有类的动态属性_Python_Django Rest Framework_Mongoengine_Metaclass - Fatal编程技术网

在Python元类中添加带有类的动态属性

在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

我使用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来说是不正确的。因此,我使用元类动态添加
子计划
字段:

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
通过这种方式,对
子计划
类的调用的使用被延迟到实际使用时,而不是解析类主体的时间,并且应该可以正常工作