如何自动创建外键对象(使用Django的Python)

huangapple go评论61阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年3月8日 17:21:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75671267.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定