Обработка представлений вложенных объектов в Django REST Framework - PullRequest
0 голосов
/ 31 марта 2020

У меня есть некоторые проблемы с обработкой вложенных сериализаторов (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 -с вложенными-объектами ) и я смотрю (https://medium.com/@raaj.akshar / создание-обратно-связанных-объектов-с- django -rest-framework-b1952ddff1 c ) и все еще имеет ответ HTTP 400:

'{"измерения": ["Это поле обязательно для заполнения."]}'

models.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

serializers.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

views.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,
)

Я что-то забыл?

Редактировать: есть конечная точка API от DRF:

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

1 Ответ

1 голос
/ 31 марта 2020

DRF не может определить источник для поля сериализатора measurement. Выполните одно из следующих действий:

  1. Добавьте related_name:
class Measurement(models.Model):
    data = models.ForeignKey(Data, on_delete=models.CASCADE, related_name='measurements')
Укажите атрибут source для поля сериализатора
class DataSerializer(serializers.ModelSerializer):
    measurements = MeasurementSerializer(many=True, source='measurement_set')

Делайте одно или другое, но не оба.

Кроме того, в вашей функции создания есть логическая ошибка

    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

...