2017-06-18 37 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