Django REST Framework嵌套资源键“id”无法访问

问题描述 投票:11回答:3

所以我有以下结构:

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的新手)


解决方案:刚刚发现ID首先没有显示的原因是因为我必须在这样的字段中声明它:希望这会有所帮助。

class ContactSerializer(serializers.ModelSerializer):

  id = serializers.IntegerField() # ← Here

  class Meta:
    model = Contact
    fields = (
      'id',
      'first_name',
      'last_name',
    )
python django django-rest-framework
3个回答
10
投票

在Django REST Framework中,AutoField字段(自动生成的字段)默认为只读。来自the docs

read_only

将其设置为True以确保在序列化表示时使用该字段,但在反序列化期间创建或更新实例时不使用该字段。

默认为False

您可以通过在shell中打印表示来查看inspecting your serializer

serializer = ClientfileSerializer()
print repr(serializer)

你可以通过在read_only=False中的id字段设置extra_kwargs来覆盖它:

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}}

3
投票

你可以尝试这样的事情:

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”键,则应该具有“instance”键。

您也可以只添加“id”而不是完整的实例/对象。


2
投票

好吧,所以我发现了一种不同的方法。我为所有者关系添加了一个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发布的完整信息集更具语义性。

© www.soinside.com 2019 - 2024. All rights reserved.