2015-03-13 70 views
7

所以我有以下結構:Django REST框架嵌套資源鍵「id」不可訪問

ClientFile屬於一個所有者(類名=聯繫人)。 我正在嘗試使用API​​創建一個Clientfile。該請求包含以下數據:

{ 
    name: "Hello!" 
    owner: { 
    id: 1, 
    first_name: "Charlie", 
    last_name: "Watson" 
    } 
} 

我根據我的結構創建了序列化程序。希望這個API調用會創建一個名爲「Hello!」的客戶端文件。和聯繫人ID 1作爲所有者:

class ContactSerializer(serializers.ModelSerializer): 
    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 

class ClientfileSerializer(serializers.ModelSerializer): 

    owner = ContactSerializer(read_only=False) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'name', 
     'owner', 
    ) 

    def create(self, validated_data): 

    owner = Contact.objects.get(pk=validated_data['owner']['id']) 

我確實進入了創建方法。但是,我需要的唯一字段(['owner']['id'])無法訪問。如果我做print ['owner']['first_name']它確實返回'查理'。但由於某些原因ID似乎無法訪問...

任何原因爲什麼會發生這種情況?我錯過了什麼嗎? (我是新來的Django)


SOLUTION:剛剛發現爲什麼ID並沒有在第一時間顯示的原因是因爲我不得不宣佈它在像這樣的字段:希望這有助於。

class ContactSerializer(serializers.ModelSerializer): 

    id = serializers.IntegerField() # ← Here 

    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 

回答

1

好吧所以我找到了一種可行的方法。 我爲所有者關係添加了一個IntegerField序列化器。我還必須將所有者關係設置爲read_only = True。

這是我通過POST發送JSON:

{ 
    name: "Hello!" 
    owner_id: 1 
} 

這是我的串行:

class ClientfileSerializer(serializers.ModelSerializer): 

    owner_id = serializers.IntegerField() 
    owner = ContactSerializer(read_only=True) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'owner_id', 
     'owner', 
    ) 

似乎比第一種方式少很酷,但它的工作。 另外我不想創建一個新的所有者,但只需選擇一個已經在數據庫中的一個。所以也許它更具語義,只有ID,而不是通過Json發佈的全部信息。

7

在Django中REST框架AutoField字段(那些自動生成的)被默認爲只讀的。從the docs

read_only

將其設置爲True以確保當 序列化的表示領域被使用,但在創建或 反序列化過程中更新實例時,不使用。

默認爲False

您可以通過inspecting your serializer通過在外殼印花表示看到這一點:

serializer = ClientfileSerializer() 
print repr(serializer) 

您可以覆蓋這個由extra_kwargs設置read_only=False對id字段:

class ContactSerializer(serializers.ModelSerializer): 
    class Meta: 
    model = Contact 
    fields = (
     'id', 
     'first_name', 
     'last_name', 
    ) 
    extra_kwargs = {'id': {'read_only': False}} 

class ClientfileSerializer(serializers.ModelSerializer): 

    owner = ContactSerializer(read_only=False) 

    class Meta(): 
    model = Clientfile 
    fields = (
     'id', 
     'name', 
     'owner', 
    ) 
    extra_kwargs = {'id': {'read_only': False}} 
+0

我試過了。它解決了問題,但又創建了另一個問題:現在我無法創建聯繫人。它會拋出一個錯誤,指出ID字段是必需的... – MonsieurNinja 2015-03-16 08:52:31

+0

您是否嘗試將只讀應用於clientfileserializer的id字段? – br3w5 2015-03-16 12:49:08

+0

我和@MonsieurNinja有同樣的問題,這使得需要手動設置ID。 – Sem 2017-04-07 14:11:31

2

你可以嘗試這樣的事情:

class YourModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = YourModel 
     fields = ('id', 'field1', 'field2') 

    def to_internal_value(self, data): 
     """ 
     Dict of native values <- Dict of primitive datatypes. 
     Add instance key to values if `id` present in primitive dict 
     :param data: 
     """ 
     obj = super(YourModelSerializer, self).to_internal_value(data) 
     instance_id = data.get('id', None) 
     if instance_id: 
      obj['instance'] = YourModel.objects.get(id=instance_id) 
     return obj 

然後在串行驗證的數據,你應該有一個「實例」鍵,如果request.data有「身份證」的關鍵。

此外,您可以添加只是「ID」,而不是完整的實例/對象。