2017-06-18 36 views
3

一些背景

我有以下的Django/Python的片断:类引用在Python

from rest_framework import serializers 
from .models import Profile, Task 

class Serializable(): 
    types = {} 
    def __init__(self, objectid): 
     self.object = self.types[objectid][0] 
     self.serializer = self.types[objectid][1] 

    def serialized(self): 
     instances = self.object.objects.all() 
     serialized = self.serializer(instances, many=True) 
     return serialized 


class ProfileSerializer(serializers.ModelSerializer): 
    class Meta: 
     oid = 'profile' 
     model = Profile 
     fields = ['login', 'status'] 
     Serializable.types[oid] = [model, <class-reference>] 

class TaskSerializer(serializers.ModelSerializer): 
    class Meta: 
     oid = 'task' 
     model = Task 
     fields = ['description', 'date', 'owner'] 
     Serializable.types[oid] = [model, <class-reference>] 

我使用Django安装了rest_framework库。我使用的一个有趣功能是ModelSerializersModelSerializers Documentation),它可以节省很多代码重复。我希望Serializable.types变量可以在运行时填充(当声明所有序列化器类时)。这一点的重点是,我不必更新我的观点,包括新型号。例如,我会打印我的模型实例的JSON表示这样的:

class QueryObject(APIView): 
    permission_classes = (AllowAny,) 

    def get(self, request, *args, **kwargs): 
     oid = request.GET['oid'] 
     serializable= Serializable(oid) 
     json = serializable.serialized 
     return JsonResponse(json) 

的问题

的主要问题是在每个Serializer类的最后一行。

Serializable.types[oid] = [model, <class-reference>] 

我试图把类的名称,ProfileSerializer例如,无济于事。我试图做同样的Meta类以外,如:

class ProfileSerializer(serializers.ModelSerializer): 
    class Meta: 
     oid = 'profile' 
     model = Profile 
     fields = ['login', 'status'] 

    Serializable.types[Meta.oid] = [Meta.model, ProfileSerializer] 

也没有成功。不知道还有什么可做的,这就是为什么我希望社区能够帮助我做到这一点。

回答

2

这实际上是定义元类的一种情况。

我从来没有找到一个信息来源,它给出了一个完整的,清晰的,令人满意的解释,说明元类是什么或它们是如何工作的。如果需要,我会尝试用这些信息加强这个答案,但是暂时我会坚持解决你目前的问题。我假设的Python 3

定义一个额外的类,即:

class ModelSerializerMeta(serializers.SerializerMetaclass): 

    def __init__(cls, class_name, base_classes, attributes): 

     super(ModelSerialiserMeta, cls).__init__(class_name, base_classes, attributes) 
     Serializer.types[cls.Meta.oid] = [cls.Meta.model, cls] 

然后用这个作为你的串行器,例如元类

class ProfileSerializer(serializers.ModelSerializer, metaclass=ModelSerializerMeta): 

    class Meta: 
     oid = 'profile' 
     model = Profile 
     fields = ['login', 'status'] 

更重要的是,创造了一些超您所有的模型序列化,分配元类出现,使您的所有串行器从超类,然后将使用整个元类继承。

+0

你能解释一下我的Serializable类最终会被调用吗?我可以看到它在ModelSerializerMeta(cls.types)中,但实际定义了cls的位置? – jhc

+0

cls由Python解释器定义。减少一句话就是ModelSerializerMeta代码在解释器遇到您的类定义时执行,然后将其传递给元类以管理类的创建。 如果这还不够,我强烈建议用python metaclasses进行搜索,因为那里写了很多东西,但我真的不知道如何更好地解释它。 –

+0

你可以像平常一样调用你的Serializable类。 –

1

Metaclasses绝对是正确的答案,除非你的代码需要python> = 3.6。从3.6开始,有一项新功能叫做init_subclass钩子。

所以,你可以这样做

class foo: 

    @classmethod 
    def __init_subclass(cls, *args, **kwargs): 
     Serializers.register_class(cls) 

每当Foo儿童是指,在Foo__init_subclass方法将被调用,通过在子类中引用作为cls

+0

我很期待这个功能。 –

+0

@SamHartman就像我问Philip,Serializable如何在这里被调用? – jhc