【问题标题】:How to send POST data to nested Serializer Django Rest Framework?如何将 POST 数据发送到嵌套的 Serializer Django Rest Framework?
【发布时间】:2017-06-13 03:46:12
【问题描述】:

我正在编写一个可以将标签添加到 todolist 的示例程序。所以我创建了标签样本。但是当我无法将它添加到 todo 序列化程序时。

这是我编写的序列化程序。

class TagSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=False, max_length=100)

    def create(self, validated_data):
        return Tag.objects.create(**validated_data)

class LocationSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    latitude = serializers.CharField(max_length=100)
    longitude = serializers.CharField(max_length=100) 

    def create(self, validated_data):
        return Location.objects.create(**validated_data)

class ToDoSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    work_id = serializers.CharField(max_length=100)
    tags = TagSerializer(many=True)
    location = LocationSerializer()

我尝试将数据作为 POST 发送到 ToDo 序列化程序。但是如何将位置和标签详细信息发送到 API 视图。

API 视图

class ToDoList(APIView):
    def post(self, request, format=None):
        serializer = ToDoSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

如何将数据作为 POST 传递给 ToDoList。我必须在 ToDoSerializer 上编写自定义帖子视图吗?

型号

class Tag(models.Model):
    name = models.CharField(max_length=100)

class Location(models.Model):
    latitude = models.CharField(max_length=100)
    longitude = models.CharField(max_length=100)

class ToDo(models.Model):
    work_id = models.CharField(max_length=100)
    tags = models.ManyToManyField(Tag)
    location = models.ForeignKey(Location)

【问题讨论】:

    标签: django python-2.7 serialization django-rest-framework


    【解决方案1】:

    您需要在 ToDoSerializer serialzier 的 create 方法中处理。文档writable-nested-representations

    你可以试试这样的:

    def create(self, validated_data):
        location_data = validated_data.pop('location')
        tag_data = validated_data.pop('tags')
        location = Location.objects.create(**location_data)
    
        instance = ToDo.objects.create(location=location, **validated_data)
    
        for dct in tag_data:
            dct.pop('id', None)
            tag, created = Tag.objects.get_or_create(**dct)
            // tag = Tag.objects.create(**dct)
            instance.tags.add(tag)
        return instance
    

    【讨论】:

    • 标签,创建= Tag.objects.get_or_create(**dct)
    【解决方案2】:

    您的请求 POST 数据应该看起来像在序列化程序中声明的嵌套结构。并且您应该为此使用模型序列化程序,否则您必须在ToDoSerializer 上提供自定义create 方法,因为常规序列化程序不知道如何使用嵌套结构/模型。

    所以,我的建议是:

    from rest_framework import serializers
    
    class ToDoSerializer(serializers.ModelSerializer):
        tags = TagSerializer(many=True)
        location = LocationSerializer()
    
        class Meta:
            model = ToDo
            fields = ('tags', 'location', 'work_id', 'id')
    

    您的帖子 json 应如下所示:

    {
        "work_id": 1,
        "tags" : [
            {"name": "blah"},
            {"name": "blahblah"}
        ],
    
        "location": {
            "latitude": 11.22,
            "longitude": 33.44
        }
    
    }
    

    【讨论】:

    • serializer.create get 被调用并返回模型实例。因此,您可以通过instance.tags_set.all() 获得这些任务 - 这种模型对的默认名称。但是您应该通过向 ManyToManyField 提供 related_name 来覆盖它。
    • 请告知标签和位置是否是 Todo 模型中的外键。我只想在要创建的新 todo 对象中引用它们。我只想创建待办事项对象而不是标签/位置对象。
    • 所以由于drf默认不支持嵌套更新/创建,所以你想要的是django-rest-framework.org/api-guide/relations/…
    • 好的,所以我必须为发布请求创建自己的创建方法。谢谢!
    猜你喜欢
    • 2014-10-03
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    • 2023-01-08
    • 2020-11-23
    • 1970-01-01
    • 2018-06-04
    • 2021-04-01
    相关资源
    最近更新 更多