2015-03-13 73 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”,而不是完整的实例/对象。