首页 > 解决方案 > 在 Django REST Framework 中处理嵌套对象表示

问题描述

我在处理嵌套序列化程序(DRF)时遇到了一些问题。

我想用这样的结构收集数据:

{
    'some_tekst': 'test_text',
    'measurements': [
        {'int_test': 1, 'char_test': '1'},
        {'int_test': 2, 'char_test': '2'}
    ]
}

我正在使用文档(https://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects),我正在查看(https://medium.com /@raaj.akshar/creating-reverse-related-objects-with-django-rest-framework-b1952ddff1c)并且仍然有 HTTP 400 响应:

'{"measurements":["此字段为必填项。"]}'

模型.py

class Data(models.Model):
    datetime = models.CharField(max_length=100)

    def __str__(self):
        return 'just testing'


class Measurement(models.Model):
    # EDIT:
    # data = models.ForeignKey(Data, on_delete=models.CASCADE) #deleted

    char_test = models.CharField(max_length=100)
    test = models.IntegerField(default=0)


    def __str__(self):
        return self.char_test

序列化程序.py:

class MeasurementSerializer(serializers.ModelSerializer):
    class Meta:
        model = Measurement
        fields = '__all__'

class DataSerializer(serializers.ModelSerializer):
    # EDIT:
    #measurements = MeasurementSerializer(many=True)
    measurements = MeasurementSerializer(many=True, source='measurement_set')

    class Meta:
        model = Data
        fields = ['datetime', 'measurements']

    # EDIT:
    #def create(self, validated_data):
    #    measurement_validated_data = validated_data.pop('measurements')
    #    data = Data.objects.create(**validated_data)
    #    Measurement.objects.create(data=data, **measurement_validated_data)
    #    return data
    def create(self, validated_data):
        measurement_validated_data = validated_data.pop('measurements')
        data = Data.objects.create(**validated_data)
        for measurement_data in measurement_validated_data:
            Measurement.objects.create(data=data, **measurement_data)
        return data

视图.py

class DataViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    serializer_class = DataSerializer
    queryset = Data.objects.all()


class MeasurementViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    serializer_class = MeasurementSerializer
    queryset = Measurement.objects.all()

还有我的简单发帖请求:

data = {
    "datetime": "testdatatime",
    "measurements": [
        {'test': 1, 'char_test': '1'},
        {'test': 2, 'char_test': '2'},
    ],
}
r = requests.post(
    'http://127.0.0.1:8000/api/data/',
    data=data,
)

我是不是忘记了什么?

编辑:有来自 DRF 的 API 端点:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "name": "Data List",
    "description": "API endpoint that allows groups to be viewed or edited.",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "datetime": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "Datetime",
                "max_length": 200
            },
            "measurements": {
                "type": "field",
                "required": true,
                "read_only": false,
                "label": "Measurements",
                "child": {
                    "type": "nested object",
                    "required": true,
                    "read_only": false,
                    "children": {
                        "id": {
                            "type": "integer",
                            "required": false,
                            "read_only": true,
                            "label": "ID"
                        },
                        "char_test": {
                            "type": "string",
                            "required": true,
                            "read_only": false,
                            "label": "Char test",
                            "max_length": 100
                        },
                        "test": {
                            "type": "integer",
                            "required": false,
                            "read_only": false,
                            "label": "Test",
                            "min_value": -2147483648,
                            "max_value": 2147483647
                        }
                    }
                }
            }
        }
    }
}

编辑 2:django 端的错误(控制台)

django_web  | Bad Request: /api/data/
django_web  | [31/Mar/2020 22:54:39] "POST /api/data/ HTTP/1.1" 400 44

标签: pythondjangoserializationdjango-rest-framework

解决方案


DRF 无法找出measurement序列化器字段的来源。执行以下操作之一:

  1. 添加一个related_name
class Measurement(models.Model):
    data = models.ForeignKey(Data, on_delete=models.CASCADE, related_name='measurements')
  1. 为序列化器字段指定一个source属性
class DataSerializer(serializers.ModelSerializer):
    measurements = MeasurementSerializer(many=True, source='measurement_set')

做一个或另一个,而不是两个。

此外,您的 create 函数中存在逻辑错误

    def create(self, validated_data):
        measurement_validated_data = validated_data.pop('measurements') # Remember, this is an array
        data = Data.objects.create(**validated_data)
        for measurement_data in measurement_validated_data:
            Measurement.objects.create(data=data, **measurement_data)
        return data


推荐阅读