django REST 中带有 many2many 的可读嵌套序列化程序

Readable nested serializer with many2many in django REST

我是 运行 一个使用 REST 将数据发送到我的 API 的 django 应用程序。

我有一个包含许多项目的网络,一个项目可以属于多个网络。

我想通过请求发送这个数据集:

payload =  {
            "name": "my great testnetwork",
            "type_network": "xyz",
            "projects" : [
                {
                    "project_name": "Brasil",
                },
                {
                    "project_name": "Sweden",
                },
            ],

            "creation_date": "2020-05-15T15:57:27.399455Z"
    } 

我不想创建 project_names,它们已经在数据库中了。我只希望它像普通 FK 一样工作,我在其中指定 project_name,它显示在我的 API 中。它应该只涉及它们。

现在的情况是,当我这样发送时,项目列表仍然是空的

这是我得到的:

{
    "id": 6,
    "name": "my great test",
    "type_network": "xyz",
    "projects": [],
    "creation_date": "2020-05-15T19:00:05.947542Z"
}

但是我需要列表中的项目。

我的序列化程序如下所示:


class NetworkSerializer(serializers.ModelSerializer):
    """Serializer for Network.

    Add extra field buildings from NestedProjectSerializer.
    """

    projects = NestedProjectSerializer(
        many=True,
        read_only=True,
        help_text="Many to many relation. Project instances expected."
    )

    class Meta:
        model = Network
        fields = (
            'id',
            'name',
            'projects',
            'creation_date',
        )

好的,所以我尝试覆盖可写嵌套序列化器的创建方法,但我想我不需要这个,对吧?因为我不想创建新对象。然后我也尝试使用 PrimaryKeyRelatedField,但我得到的错误是 pk is not valid(传递查询集时)或者它不显示项目(使用只读=True 时)。

我有点卡在这里。有人可以帮我吗?非常感谢您的时间和帮助。非常感谢!

如果需要,我很乐意提供更多代码或说明。

我的模特:


class Project(models.Model):
    project_name = models.CharField(max_length=120, primary_key=True, unique=True)
    location = models.CharField(max_length=120, null=True, blank=True)


class Network(models.Model):

    name = models.CharField(
        max_length=120,
        null=True,
        blank=True,
        help_text="Name of network. String expected."
    )

    projects = models.ManyToManyField(
        Project,
        default=None,
        blank=True,
        help_text="Many to many relation. Project instances expected."
    )

    creation_date = models.DateTimeField(
        auto_now=True
    )

我觉得我必须覆盖创建方法... project_name 是 pk 顺便说一句。

编辑:像这样发送数据:


payload =  {
            "name": "my great testnetwork",
            # "projects" : [
            #     {
            #         "project_name": "frankfurt",

            #     }
            # ],
            "projects_data" : [
                {
                    "project_name": "Brasil",

                }
            ],

            "creation_date": "2020-05-15T15:57:27.399455Z"
    }   

r = requests.request('post', 'http://localhost:8000/myendpoint', json=payload, headers=headers)
print(r.text)
print(r.status_code)

您需要将代码更新为如下:

from rest_framework import serializers

class NetworkSerializer(serializers.ModelSerializer):
    """Serializer for Network.

    Add extra field buildings from NestedProjectSerializer.
    """
    projects_data = serializers.SerializerMethodField()

    class Meta:
        model = Network
        fields = (
            'id',
            'name',
            'projects',
            'projects_data',
            'creation_date',
        )

    def get_projects_data(self, obj):
        projects = obj.projects.all()
        return NestedProjectSerializer(projects, many=True).data

希望对您有所帮助..!!

如果你定义一个嵌套的序列化器,你将在创建记录时总是卡住。由于创建方法需要来自项目序列化程序的序列化数据

参考:https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

编辑: 新序列化器

from rest_framework import serializers

class NetworkSerializer(serializers.ModelSerializer):
    """Serializer for Network.

    Add extra field buildings from NestedProjectSerializer.
    """
    projects = NestedProjectSerializer(many=True, required=False)

    class Meta:
        model = Network
        fields = (
            'id',
            'name',
            'projects',
            'projects_data',
            'creation_date',
        )

    def create(self, validated_data):
        projects = validated_data.pop("projects")
        network_obj = Network.objects.create(**validated_data)
        for project in projects:
            network_obj.projects.add(Project.objects.create(**project))
        network_obj.save()
        return network_obj

我已经根据您的要求重写了创建方法