2016-11-07 81 views
0

我使用mongoengine和Django rest框架。我的模型:用Python元類中的類添加動態屬性

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

你有,當你嘗試要麼使用線 subplans = PlanSerializer(many=True, required=False)並與元類嘗試時,該行class_obj = globals()[name]當你PlanSerializerclass本身沒有定義的問題。 (檢查我的答案在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__)方法中時,並不是所有的類初始化都已完成。例如,如果PlanSerializerPlanSerializer方法本身將使用super,則該調用將失敗 - super只能在完成類的初始化後使用。

但是,您根本不需要元類 - 您可能可以簡單地將subplans屬性設置爲描述符 - 並且可以懶惰地檢索屬性。

class PlanSerializer(serializers.DocumentSerializer): 
    class Meta: 
     model = Plan 

PlanSerializer.subplans = PlanSerializer(many=True, required=False) 

我大概說因爲如果蒙戈需要的屬性被設置初始化類本身時,這是不行的 - 如果是這樣的話,你可以嘗試訴諸描述符對象。描述符只是一個實現方法的對象,如下所示。通常通過@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類的用法產生延遲時實際使用它,而不是解析類的身體的時候,它應該工作。