英文:
How to auto create foreingKey object (python with django)
问题
我正在创建一个简单的REST API。
这是我从设备中获取的实际结果。我首先创建组和选项,然后关联它们,但我希望在创建设备的同时创建选项。
我现在从设备中获取的结果如下:
[
{
"id_device": "a099d2ce-812b-4d85-8c8b-cfe71057fbe7",
"group": {
"id_group": "39407ef6-1a3e-4965-9b61-96f6c40b76b3",
"name": "Cozinha"
},
"options": [
{
"id_option": "1b383a37-5229-4ae0-9649-f76aa32eeda0",
"name": "1",
"identifier": "POWER1"
},
{
"id_option": "4ff5406a-8c7b-4517-9ec0-14fd4f68f30b",
"name": "2",
"identifier": "POWER2"
},
{
"id_option": "a541216d-f509-4461-85ca-444491ac9217",
"name": "3",
"identifier": "POWER3"
},
{
"id_option": "3debe828-edd6-4d83-bfd8-2776a1594380",
"name": "4",
"identifier": "POWER4"
}
],
"name": "Interruptor 4",
"identifier": "identifiertest"
}
]
我的models.py:
from uuid import uuid4
from django.db import models
class Options(models.Model):
id_option = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
identifier = models.CharField(max_length=255)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Groups(models.Model):
id_group = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Devices(models.Model):
id_device = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
identifier = models.CharField(max_length=255)
options = models.ManyToManyField(Options)
group = models.ForeignKey(Groups, on_delete=models.CASCADE, default="")
viewsets:
from rest_framework import viewsets
from devices.api import serializers
from devices import models
class DevicesViewsets(viewsets.ModelViewSet):
serializer_class = serializers.DevicesSerializer
queryset = models.Devices.objects.all()
class OptionsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.OptionsSerializer
queryset = models.Options.objects.all()
class GroupsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.GroupsSerializer
queryset = models.Groups.objects.all()
serializers:
from rest_framework import serializers
from devices import models
class OptionsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Options
fields = '__all__'
class GroupsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Groups
fields = '__all__'
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
我发送以下内容来创建设备:
{
"group": {
"name": "newgroup"
},
"options": [
{
"name": "teste1",
"identifier": "teste1"
}
],
"name": "teste1",
"identifier": "teste1"
}
但是出现了以下错误:
在/devices/发生了断言错误
默认情况下,.create()
方法不支持可写的嵌套字段。
为devices.api.serializers.DevicesSerializer
编写一个显式的.create()
方法,或在嵌套的序列化字段上设置read_only=True
。
请求方法:POST
请求网址:http://127.0.0.1:8000/devices/
Django版本:4.1.7
异常类型:断言错误
异常值:默认情况下,.create()
方法不支持可写的嵌套字段。为devices.api.serializers.DevicesSerializer
编写一个显式的.create()
方法,或在嵌套的序列化字段上设置read_only=True
。
我知道解决方案在这里,但我不知道如何解决。我尝试了一些来自互联网的解决方案,但都没有成功,所以有人能帮助我吗?
英文:
I'm creating a simple rest api
This is my actual result from devices, i create first the group and options, and then associate, but i want to create the options at the same time i create the device.
My result from devices right now
[
{
"id_device": "a099d2ce-812b-4d85-8c8b-cfe71057fbe7",
"group": {
"id_group": "39407ef6-1a3e-4965-9b61-96f6c40b76b3",
"name": "Cozinha"
},
"options": [
{
"id_option": "1b383a37-5229-4ae0-9649-f76aa32eeda0",
"name": "1",
"identifier": "POWER1"
},
{
"id_option": "4ff5406a-8c7b-4517-9ec0-14fd4f68f30b",
"name": "2",
"identifier": "POWER2"
},
{
"id_option": "a541216d-f509-4461-85ca-444491ac9217",
"name": "3",
"identifier": "POWER3"
},
{
"id_option": "3debe828-edd6-4d83-bfd8-2776a1594380",
"name": "4",
"identifier": "POWER4"
}
],
"name": "Interruptor 4",
"identifier": "identifiertest"
},
]
my models.py
from uuid import uuid4
from django.db import models
class Options(models.Model):
id_option = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
identifier = models.CharField(max_length=255)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Groups(models.Model):
id_group = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Devices(models.Model):
id_device = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)
identifier = models.CharField(max_length=255)
options = models.ManyToManyField(Options)
group = models.ForeignKey(Groups, on_delete=models.CASCADE, default="")
viewsets
from rest_framework import viewsets
from devices.api import serializers
from devices import models
class DevicesViewsets(viewsets.ModelViewSet):
serializer_class = serializers.DevicesSerializer
queryset = models.Devices.objects.all()
class OptionsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.OptionsSerializer
queryset = models.Options.objects.all()
class GroupsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.GroupsSerializer
queryset = models.Groups.objects.all()
serializers
from rest_framework import serializers
from devices import models
class OptionsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Options
fields = '__all__'
class GroupsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Groups
fields = '__all__'
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
I send this to create the device
{
"group": {
"name": "newgroup"
},
"options": [
{
"name": "teste1",
"identifier": "teste1"
}
],
"name": "teste1",
"identifier": "teste1"
}
but get this error:
> AssertionError at /devices/
> The .create()
method does not support writable nested fields by default.
> Write an explicit .create()
method for serializer devices.api.serializers.DevicesSerializer
, or set read_only=True
on nested serializer fields.
> Request Method: POST
> Request URL: http://127.0.0.1:8000/devices/
> Django Version: 4.1.7
> Exception Type: AssertionError
> Exception Value:
> The .create()
method does not support writable nested fields by default.
> Write an explicit .create()
method for serializer devices.api.serializers.DevicesSerializer
, or set read_only=True
on nested serializer fields.
I know the response is here, but i dont know how to do it.
I try some solutions from internet but none with success, so can someone help me?
答案1
得分: 1
serializer.py
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
def create(self, validated_data):
group_data = validated_data.pop('group')
options_data = validated_data.pop('options')
group, _ = models.Groups.objects.get_or_create(**group_data)
options = [models.Options.objects.create(**option_data) for option_data in options_data]
device = models.Devices.objects.create(group=group, **validated_data)
device.options.set(options)
return device
viewsets.py
from rest_framework import viewsets
from devices.api import serializers
from devices import models
class DevicesViewsets(viewsets.ModelViewSet):
serializer_class = serializers.DevicesSerializer
queryset = models.Devices.objects.all()
def perform_create(self, serializer):
serializer.save()
class OptionsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.OptionsSerializer
queryset = models.Options.objects.all()
class GroupsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.GroupsSerializer
queryset = models.Groups.objects.all()
英文:
serializer.py
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
def create(self, validated_data):
group_data = validated_data.pop('group')
options_data = validated_data.pop('options')
group, _ = models.Groups.objects.get_or_create(**group_data)
options = [models.Options.objects.create(**option_data) for option_data in options_data]
device = models.Devices.objects.create(group=group, **validated_data)
device.options.set(options)
return device
viewsets.py:
from rest_framework import viewsets
from devices.api import serializers
from devices import models
class DevicesViewsets(viewsets.ModelViewSet):
serializer_class = serializers.DevicesSerializer
queryset = models.Devices.objects.all()
def perform_create(self, serializer):
serializer.save()
class OptionsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.OptionsSerializer
queryset = models.Options.objects.all()
class GroupsViewsets(viewsets.ModelViewSet):
serializer_class = serializers.GroupsSerializer
queryset = models.Groups.objects.all()
答案2
得分: 0
你是对的,答案就在这里。基本上,你需要为你的 DevicesSerializer
类提供一个 def create(self, validated_data)
方法。
以下是一些可能会有帮助的代码示例:
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
def create(self, validated_data):
options_data = validated_data.pop("options")
device = models.Devices.objects.create(**validated_data) # 或者你可以手动将字段/数据作为kwargs传递
for option_data in options_data:
models.Options.objects.create(device=device, **option_data)
return device
基本上,你需要手动保存基本对象(Device
),然后手动迭代选项数据并创建每个选项,将它们指向新创建的 device
。
英文:
You are right, the answer is in there. Basically you have to provide a def create(self, validated_data)
method to your DevicesSerializer
class.
Here is something that could help:
class DevicesSerializer(serializers.ModelSerializer):
group = GroupsSerializer()
options = OptionsSerializer(many=True)
class Meta:
model = models.Devices
fields = '__all__'
def create(self, validated_data):
options_data = validated_data.pop("options")
device = models.Devices.objects.create(**validated_data) # or you can manually pass the fields/data as kwargs
for option_data in options_data:
models.Options.objects.create(device=device, **option_data)
return device
Basically, you need to manually save the base object (Device
) and then manually iterate over the options data and create each of them pointing to the newly created device
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论