Django REST Framework 嵌套资源键 "id" 无法访问
Django REST Framework nested resource key "id" unaccessible
所以我有以下结构:
ClientFile 属于所有者(class 姓名 = 联系人)。
我正在尝试使用 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']
它会做 return 'Charlie'。但是由于某些原因,ID似乎无法访问...
为什么会发生这种情况?我错过了什么吗? (我是 Django 的新手)
解决方案:刚刚发现 ID 最初没有显示的原因是因为我必须像这样在字段中声明它:希望这有帮助。
class ContactSerializer(serializers.ModelSerializer):
id = serializers.IntegerField() # ← Here
class Meta:
model = Contact
fields = (
'id',
'first_name',
'last_name',
)
在 Django REST Framework AutoField
字段(自动生成的字段)默认为只读。来自 the docs:
read_only
Set this to True
to ensure that the field is used when
serializing a representation, but is not used when creating or
updating an instance during deserialization.
Defaults to False
您可以通过 inspecting your serializer 通过在您的 shell 中打印表示来查看此内容:
serializer = ClientfileSerializer()
print repr(serializer)
您可以通过针对 extra_kwargs
中的 id 字段设置 read_only=False
来覆盖它:
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}}
好的,所以我找到了一种不同的方法。
我为所有者关系添加了一个 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',
)
它似乎不如第一种方式酷,但它确实起作用了。
另外,我不想创建一个新的所有者,而只是 select 一个已经在数据库中的所有者。因此,仅具有 ID 而不是通过 Json.
发布的全套信息可能更具语义性
您可以尝试这样的操作:
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" 而不是完整的 instance/object。
投票最高的答案确实解决了问题,但它引发了一个新问题,如评论中所述,我们无法再创建新记录,因为它会抛出 ac 异常,说明需要。我们可以将 id 设置为 required=False 然后 id 将在 validated_data 中可用,并且不需要手动设置它
id = serializers.IntegerField(required=False) <- Like this
class Meta:
model = Details
fields = ('id', 'product_name', 'description', 'specification', 'make_model',
'brand', 'quantity',)
所以我有以下结构:
ClientFile 属于所有者(class 姓名 = 联系人)。 我正在尝试使用 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']
它会做 return 'Charlie'。但是由于某些原因,ID似乎无法访问...
为什么会发生这种情况?我错过了什么吗? (我是 Django 的新手)
解决方案:刚刚发现 ID 最初没有显示的原因是因为我必须像这样在字段中声明它:希望这有帮助。
class ContactSerializer(serializers.ModelSerializer):
id = serializers.IntegerField() # ← Here
class Meta:
model = Contact
fields = (
'id',
'first_name',
'last_name',
)
在 Django REST Framework AutoField
字段(自动生成的字段)默认为只读。来自 the docs:
read_only
Set this to
True
to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.Defaults to
False
您可以通过 inspecting your serializer 通过在您的 shell 中打印表示来查看此内容:
serializer = ClientfileSerializer()
print repr(serializer)
您可以通过针对 extra_kwargs
中的 id 字段设置 read_only=False
来覆盖它:
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}}
好的,所以我找到了一种不同的方法。 我为所有者关系添加了一个 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',
)
它似乎不如第一种方式酷,但它确实起作用了。 另外,我不想创建一个新的所有者,而只是 select 一个已经在数据库中的所有者。因此,仅具有 ID 而不是通过 Json.
发布的全套信息可能更具语义性您可以尝试这样的操作:
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" 而不是完整的 instance/object。
投票最高的答案确实解决了问题,但它引发了一个新问题,如评论中所述,我们无法再创建新记录,因为它会抛出 ac 异常,说明需要。我们可以将 id 设置为 required=False 然后 id 将在 validated_data 中可用,并且不需要手动设置它
id = serializers.IntegerField(required=False) <- Like this
class Meta:
model = Details
fields = ('id', 'product_name', 'description', 'specification', 'make_model',
'brand', 'quantity',)