Django Framework Rest запись вложенными сериализатору с несколькими вложенными объектами

Обновить

December 2018

Просмотры

772 раз

5

Я пытаюсь создать записываемый вложенный сериалайзер. Моя материнская модель игры и вложенные модели измерения. Я пытаюсь опубликовать эти данные в моей DRF приложения с помощью AJAX. Однако при попытке опубликовать данные, вложенные измерения пустые OrderedDict ().

Вот мои модели:

class Game(models.Model):
    start_timestamp = models.DateTimeField(auto_now_add=False)
    end_timestamp = models.DateTimeField(auto_now_add=False)
    date_added = models.DateTimeField(auto_now_add=True)


class Measurement(models.Model):
    game = models.ForeignKey(Game, on_delete=models.PROTECT, related_name='measurements')
    measurement_type = models.CharField(max_length=56)
    measurement = models.CharField(max_length=56)
    timestamp = models.DateTimeField(auto_now_add=False)
    date_added = models.DateTimeField(auto_now_add=True)

Вот мои сериализаторы:

class MeasurementSerializer(serializers.ModelSerializer):
        timestamp = serializers.DateTimeField(input_formats=(['%Y-%m-%d %H:%M:%S.%Z', 'iso-8601']), required=False)

        class Meta:
            model = Measurement
            fields = ('measurement_type', 'measurement', 'timestamp')


class GameSerializer(serializers.ModelSerializer):
    start_timestamp = serializers.DateTimeField(input_formats=(['%Y-%m-%d %H:%M:%S.%Z', 'iso-8601']))
    end_timestamp = serializers.DateTimeField(input_formats=(['%Y-%m-%d %H:%M:%S.%Z', 'iso-8601']))
    measurements = MeasurementSerializer(many=True)

    class Meta:
        model = Game
        fields = ('id', 'start_timestamp', 'end_timestamp', 'measurements')

    def create(self, validated_data):
        measurements = validated_data.pop('measurements')
        game = Game.objects.create(**validated_data)
        for measurement in measurements:
            Measurement.objects.create(game=game, **measurement)
        return game

На мой взгляд для игры заключается в следующем:

class GameList(generics.ListCreateAPIView):
    queryset = Game.objects.all()
    serializer_class = GameSerializer

Я последовал этот учебник для структуры.

Я пытаюсь отправить к этому API через AJAX, код ниже:

 $.ajax({
         url: base_url + '/games/',
         dataType: "json",
         data: {
                "start_timestamp": "2016-02-16 14:51:43.000000",
                "end_timestamp": "2016-02-16 14:53:43.000000",
                "measurements":[
                    {'measurement_type':'type1', 'measurement':'71', 'timestamp':'2016-02-16 14:53:43.000000'},
                    {'measurement_type':'type1', 'measurement':'72', 'timestamp':'2016-02-16 14:54:43.000000'},
                    {'measurement_type':'type1', 'measurement':'73', 'timestamp':'2016-02-16 14:55:43.000000'},
                ]
                },
         type: 'POST'
     })
     .error(function(r){})
     .success(function(data){})
 });

На размещение этой информации, я нахожу в методе создания внутри GameSerializer, что validate_data.pop ( «измерения») содержит список 3 упорядоченных словарей (OrderedDict ()), которые пусты.

UPDATE: Я обнаружил, что что initial_data приходящая через request.data структурирована следующим образом:

'emotion_measurements[0][measurement_type]' (4397175560) = {list} ['type1']
'emotion_measurements[0][measurement]' (4397285512) = {list} ['71']
'emotion_measurements[0][timestamp]' (4397285600) = {list} ['2016-02-16 14:53:43.000000']
'emotion_measurements[1][measurement_type]' (4397175040) = {list} ['type1']
'emotion_measurements[1][measurement]' (4397285864) = {list} ['72']
'emotion_measurements[1][timestamp]' (4397285952) = {list} ['2016-02-16 14:54:43.000000']
'emotion_measurements[2][measurement_type]' (4397175040) = {list} ['type1']
'emotion_measurements[2][measurement]' (4397285864) = {list} ['73']
'emotion_measurements[2][timestamp]' (4397285952) = {list} ['2016-02-16 14:55:43.000000']

Кто-нибудь сталкивался с такой вопрос раньше? Спасибо!

UPDATE # 2

Я был в состоянии решить эту проблему (хотя я считаю, что это больше, чем обходной путь решения), добавив следующее мое MeasurementSerializer:

def to_internal_value(self, data):
        formatted_data = json.dumps(data)
        formatted_data = formatted_data.replace("[", "").replace("]","")
        formatted_data = json.loads(formatted_data)
        return formatted_data

Данные измерений, поступающие был QueryDict, когда я считаю, что я нуждался в Dict. Были также некоторые дополнительные скобки вокруг ключа и значения, так что я должен был удалить их также.

Тем не менее ищу лучший ответ, чем это!

1 ответы

0

Проблема здесь находится на передней торцевой стороне. По умолчанию сервер интерпретирует данные , как application/x-www-form-urlencodedи для того , чтобы понять , что вы отправляете его json, вы должны указать contentTypeв вашем $.ajaxзапросе:

$.ajax({
     url: base_url + '/games/',
     dataType: "json",
     data: {...},
     contentType: 'application/json; charset=UTF-8',  // add this line
     type: 'POST'
 })
 .error(function(r){})
 .success(function(data){});

Теперь ваш validated_data.pop('measurements')в create()методе из ваших GameSerializerдолжен давать три объекта с вашим measurements(но не забудьте повторить свой обходной путь от Update # 2).