Django Rest框架错误AssertionError `child` is a required argument

Евг*_*чак 5 python django django-rest-framework

在开发我的应用程序时我遇到了一个问题

\n\n
AssertionError at /api/update/\n`child` is a required argument.\nRequest Method: GET\nRequest URL:    http://45.56.80.77/api/update/?token=1234567&ifloorplan=2\nDjango Version: 3.0.6\nException Type: AssertionError\nException Value:    \n`child` is a required argument.\nException Location: /root/Env/ifloorplan/lib/python3.8/site-packages/rest_framework/serializers.py in __init__, line 591\nPython Executable:  /usr/local/bin/uwsgi\nPython Version: 3.8.2\nPython Path:    \n[\'.\',\n \'\',\n \'/usr/lib/python38.zip\',\n \'/usr/lib/python3.8\',\n \'/usr/lib/python3.8/lib-dynload\',\n \'/root/Env/ifloorplan/lib/python3.8/site-packages\']\nServer time:    Mon, 1 Jun 2020 07:18:31 +0000\n
Run Code Online (Sandbox Code Playgroud)\n\n

也就是说,我尝试在数据库中更新并创建此类记录

\n\n
[\n    {\n        "id": 2,\n        "level": [\n            {\n                "id": 2,\n                "plan_level": {\n                    "img": null,\n                    "img_height": null,\n                    "img_width": null,\n                    "position_x": null,\n                    "position_y": null,\n                    "level": null\n                },\n                "images": [\n                    {\n                        "id": 2,\n                        "cam": [\n                            {\n                                "id": 2,\n                                "ken_burns": {\n                                    "effect": null,\n                                    "start_pos_x": null,\n                                    "start_pos_y": null,\n                                    "finish_pos_x": null,\n                                    "finish_pos_y": null,\n                                    "start_width": null,\n                                    "start_height": null,\n                                    "finish_width": null,\n                                    "finish_height": null,\n                                    "cam": null\n                                },\n                                "rotation": 0.34,\n                                "pos_x": 21.0,\n                                "pos_y": 234.0,\n                                "width": 1234.0,\n                                "height": 234.0,\n                                "img": 2\n                            },\n                            {\n                                "id": 3,\n                                "ken_burns": {\n                                    "effect": null,\n                                    "start_pos_x": null,\n                                    "start_pos_y": null,\n                                    "finish_pos_x": null,\n                                    "finish_pos_y": null,\n                                    "start_width": null,\n                                    "start_height": null,\n                                    "finish_width": null,\n                                    "finish_height": null,\n                                    "cam": null\n                                },\n                                "rotation": 4.0,\n                                "pos_x": 354.0,\n                                "pos_y": 345.0,\n                                "width": 345.0,\n                                "height": 345.0,\n                                "img": 2\n                            }\n                        ],\n                        "img": "/media/ifloorplans_source/test.jpg",\n                        "level": 2\n                    }\n                ],\n                "tabLabel": "1 st",\n                "plan": 2\n            }\n        ],\n        "textColor": "WQ2123",\n        "bgColor": "SA2132",\n        "camColor": "CV1234",\n        "author": 14\n    }\n]\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我的序列化器.py

\n\n
from django.contrib.auth.models import User\nfrom .models import (\n    IFloorPlan,\n    Level,\n    PlanImg,\n    Image,\n    Cam,\n    KenBurns,\n\n)\nfrom rest_framework import serializers\n\n\nclass KenBurnsSerializer(serializers.ListSerializer):\n    # plan = IFloorPlanSerializer(required=True)\n\n    def update(self, instance, validated_data):\n        pass\n\n    def create(self, validated_data):\n        predictions = [KenBurns(**item) for item in validated_data]\n        return KenBurns.objects.bulk_create(predictions)\n\n    class Meta:\n        model = KenBurns\n        fields = \'__all__\'\n\n\nclass CamSerializer(serializers.ListSerializer):\n    ken_burns = KenBurnsSerializer()\n\n    def update(self, instance, validated_data):\n        pass\n\n    def create(self, validated_data):\n        predictions = [Cam(**item) for item in validated_data]\n        return Cam.objects.bulk_create(predictions)\n\n\n\n    class Meta:\n        model = Cam\n        fields = \'__all__\'\n\n\n\nclass ImageSerializer(serializers.ListSerializer):\n    cam = CamSerializer(many=True)\n\n    def update(self, instance, validated_data):\n        pass\n\n    def create(self, validated_data):\n        predictions = [Image(**item) for item in validated_data]\n        return Image.objects.bulk_create(predictions)\n\n\n    class Meta:\n        model = Image\n        fields = \'__all__\'\n\n\nclass PlanImgSerializer(serializers.ListSerializer):\n    # plan = IFloorPlanSerializer(required=True)\n\n    def update(self, instance, validated_data):\n        pass\n\n    def create(self, validated_data):\n        predictions = [PlanImg(**item) for item in validated_data]\n        return PlanImg.objects.bulk_create(predictions)\n\n    class Meta:\n        model = PlanImg\n        fields = \'__all__\'\n\n\nclass LevelSerializer(serializers.ListSerializer):\n    plan_level = PlanImgSerializer()\n    images = ImageSerializer(many=True)\n\n    def update(self, instance, validated_data):\n        pass\n\n    def create(self, validated_data):\n        predictions = [Level(**item) for item in validated_data]\n        return Level.objects.bulk_create(predictions)\n\n    class Meta:\n        model = Level\n        fields = \'__all__\'\n\nclass IFloorPlanSerializer(serializers.Serializer):\n    level = LevelSerializer(many=True)\n\n    class Meta:\n        list_serializer_class = LevelSerializer\n        model = IFloorPlan\n        fields = \'__all__\'\n\n\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

视图.py

\n\n
from django.shortcuts import render\nfrom django.http.response import JsonResponse\nfrom rest_framework import status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.response import Response\nfrom .serializers import IFloorPlanSerializer\nfrom rest_framework.views import APIView\nfrom .models import IFloorPlan\nfrom public.models import ApiToken\n# Create your views here.\n\n\n@api_view([\'GET\', ])\ndef get_ifloorplan(request):\n    if "token" in request.GET and "ifloorplan" in request.GET:\n        token_obj = ApiToken.objects.filter(token=request.GET["token"])\n        if token_obj:\n            plans = IFloorPlan.objects.filter(id=request.GET["ifloorplan"])\n            serializer = IFloorPlanSerializer(plans, many=True)\n            return Response(serializer.data)\n        else:\n            return JsonResponse({"message": "Don\'t valid token"}, status=status.HTTP_400_BAD_REQUEST)\n    else:\n        return JsonResponse({"message": "Don\'t valid GET parameter"}, status=status.HTTP_400_BAD_REQUEST)\n\n\n@api_view([\'PUT\', \'GET\',])\ndef update_ifloorplan(request):\n    if "token" in request.GET and "ifloorplan" in request.GET:\n        token_obj = ApiToken.objects.filter(token=request.GET["token"])\n        if token_obj:\n            plans = IFloorPlan.objects.filter(id=request.GET["ifloorplan"])\n            serializer = IFloorPlanSerializer(plans, data=request.data, many=True)\n            if serializer.is_valid():\n                serializer.save()\n                return JsonResponse({"message": "Update successful"}, status=status.HTTP_200_OK)\n            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n        else:\n            return JsonResponse({"message": "Don\'t valid token"}, status=status.HTTP_400_BAD_REQUEST)\n    else:\n        return JsonResponse({"message": "Don\'t valid GET parameter"}, status=status.HTTP_400_BAD_REQUEST)\n\n\n\n@api_view([\'POST\', \'GET\'])\ndef create_ifloorplan(request):\n    if "token" in request.GET:\n        token_obj = ApiToken.objects.get(token=request.GET["token"])\n        if token_obj:\n            plans = IFloorPlan(author=token_obj.user)\n            serializer = IFloorPlanSerializer(plans, data=request.data, many=True)\n            if serializer.is_valid():\n                serializer.save()\n                return JsonResponse({"message": "Create successful"}, status=status.HTTP_200_OK)\n            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n        else:\n            return JsonResponse({"message": "Don\'t valid token"}, status=status.HTTP_400_BAD_REQUEST)\n    else:\n        return JsonResponse({"message": "Don\'t valid GET parameter"}, status=status.HTTP_400_BAD_REQUEST)\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

模型.py

\n\n
from django.db import models\nfrom django.contrib.auth.models import User\n\n\nclass IFloorPlan(models.Model):\n    textColor = models.CharField(max_length=10, blank=True, null=True)\n    bgColor = models.CharField(max_length=10, blank=True, null=True)\n    camColor = models.CharField(max_length=10, blank=True, null=True)\n    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)\n\nclass Level(models.Model):\n    plan = models.ForeignKey(IFloorPlan, on_delete=models.CASCADE, related_name=\'level\', blank=True, null=True)\n    tabLabel = models.CharField(max_length=100, blank=True, null=True)\n\nclass PlanImg(models.Model):\n    level = models.ForeignKey(Level, on_delete=models.CASCADE, related_name=\'plan_level\', blank=True, null=True)\n    img = models.ImageField(upload_to=\'ifloorplans_source/\', blank=True, null=True)\n    img_height = models.FloatField(blank=True, null=True)\n    img_width = models.FloatField(blank=True, null=True)\n    position_x = models.FloatField(blank=True, null=True)\n    position_y = models.FloatField(blank=True, null=True)\n\nclass Image(models.Model):\n    level = models.ForeignKey(Level, on_delete=models.CASCADE, related_name=\'images\', blank=True, null=True)\n    img = models.ImageField(upload_to=\'ifloorplans_source/\', blank=True, null=True)\n\nclass Cam(models.Model):\n    rotation = models.FloatField(blank=True, null=True)\n    pos_x = models.FloatField(blank=True, null=True)\n    pos_y = models.FloatField(blank=True, null=True)\n    img = models.ForeignKey(Image, on_delete=models.CASCADE, related_name=\'cam\', blank=True, null=True)\n    width = models.FloatField(blank=True, null=True)\n    height = models.FloatField(blank=True, null=True)\n\nclass KenBurns(models.Model):\n    cam = models.ForeignKey(Cam, on_delete=models.CASCADE, related_name=\'ken_burns\', blank=True, null=True)\n    effect = models.BooleanField(default=False, blank=True, null=True)\n    start_pos_x = models.FloatField(blank=True, null=True)\n    start_pos_y = models.FloatField(blank=True, null=True)\n    finish_pos_x = models.FloatField(blank=True, null=True)\n    finish_pos_y = models.FloatField(blank=True, null=True)\n    start_width = models.FloatField(blank=True, null=True)\n    start_height = models.FloatField(blank=True, null=True)\n    finish_width = models.FloatField(blank=True, null=True)\n    finish_height = models.FloatField(blank=True, null=True)\n\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

我第二天就已经可以\xe2\x80\x99解决这个问题了\n一开始出现了无法更新多个表的问题。所以我决定使用列表序列化器来更新和创建表中的记录。我会很高兴得到任何帮助

\n

小智 5

ListSerializer 基本上是其他序列化器的容器,并且只能包含一个特定的序列化器,该序列化器被设置为“子”序列化器。

LevelSerializer扩展了 ListSerializer 但不提供 this 子属性。这通常不是使用 ListSerializer 的方式 - 仅在非常特殊的情况下才需要扩展它。在常见情况下,您希望为模型创建一个普通的序列化器Level并将其设置为带有参数的字段many=True。这将在后台创建一个列表序列化器,如文档中所述

您犯了好几次错误,但这应该让您朝着正确的方向开始:

class LevelSerializer(serializers.ModelSerializer)
    class Meta:
        model = Level
        fields = ('plan', 'tabLabel')

class IFloorPlanSerializer(serializers.Serializer):
    level = LevelSerializer(many=True)
Run Code Online (Sandbox Code Playgroud)

扩展列表序列化器并提供自定义更新方法:

class LevelListSerializer(serializers.ListSerializer):
    child = LevelSerializer()

    def update(self, instance, validated_data):
        # instance is the queryset, validated_data a list of dicts
        # See [the documentation](https://github.com/encode/django-rest-framework/blob/master/docs/api-guide/serializers.md#customizing-multiple-update) for an example.

class IFloorPlanSerializer(serializers.Serializer):
    level = LevelListSerializer()
Run Code Online (Sandbox Code Playgroud)

  • 我按照你写的做了,但遇到了另一个问题“许多= True的序列化器默认不支持多次更新,只支持多次创建。对于更新,不清楚如何处理插入和删除。如果需要支持多次更新,使用`ListSerializer`类并覆盖`.update()`,这样你就可以准确地指定行为。”我之前遇到的错误 AssertionError `child` is a required argument (2认同)