The problem you have there is that when you try to either use the line
subplans = PlanSerializer(many=True, required=False)
and when trying with the metaclass, the line class_obj = globals()[name]
when your PlanSerializerclass itself was not defined yet. (Check my answer at How is super() in Python 3 implemented?)
The correct way to do that in the metaclass would be to call the superclass's new first - that returns you the actual class object, and then call that object - something along:
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
But that is both not needed, and might still have issues - as not all the class initialization is completed while you are still inside the metaclass's __new__
(or even __init__
) methods. For example, if the __init__
method of PlanSerializer
itself would make use of super
, that call would fail - super
can only be used after class has been fully initialized.
However, you don't need a metaclass at all for that - you probably can simply set the subplans
attribute as a descriptor - and retrieve the attribute lazily.
class PlanSerializer(serializers.DocumentSerializer):
class Meta:
model = Plan
PlanSerializer.subplans = PlanSerializer(many=True, required=False)
I said probably because this won't work if Mongo needs the attribute to be set when initializing the class itself - if that is the case, you can try resorting to a descriptor object. A descriptor is simply an object that implements the __get__
method, like below. That is usually done with the @property
decorator, but that would not work for class level attributes, which you need for this case.
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
In that way the usage of the call to the Subplans
class is delayed to when it is actually used, instead of the time of parsing the class body, and it should work.