python

时间:2017-06-18 15:23:38

标签: python django django-rest-framework

一些上下文

我有以下django / 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>]

我正在使用安装了rest_framework库的Django。我使用的一个有趣的功能是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 个答案:

答案 0 :(得分: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']

更好的是,为所有模型序列化器创建一些超类,在那里分配元类,使所有序列化程序继承自该超类,然后在整个类中使用元类。

答案 1 :(得分:1)

除非您的代码需要python&gt; = 3.6,否则元类绝对是正确的答案。从3.6开始,有一个名为__init_subclass__ hook的新功能。

所以你可以做点什么

class foo:

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

每当定义Foo的孩子时,都会调用__init_subclass__上的Foo方法,并将子类引用传递为cls