I'm trying to create a writable nested serializer. My parent model is Game and the nested models are Measurements. I am trying to post this data to my DRF application using AJAX. However, when try to post the data, the nested Measurements are empty OrderedDict().
Here are my models:
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)
Here are my serializers:
class MeasurementSerializer(serializers.ModelSerializer):timestamp = serializers.DateTimeField(input_formats=(['%Y-%m-%d %H:%M:%S.%Z', 'iso-8601']), required=False)class Meta:model = Measurementfields = ('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 = Gamefields = ('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
My view for Game is the following:
class GameList(generics.ListCreateAPIView):queryset = Game.objects.all()serializer_class = GameSerializer
I followed this tutorial for the structure.
I am trying to post to this API via AJAX, the code below:
$.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){})});
On posting this data, I find in the create method within the GameSerializer that the validate_data.pop('measurements') contains a list of 3 ordered dictionaries (OrderedDict()) that are empty.
UPDATE: I've found that that the initial_data coming in via request.data is structured like so:
'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']
Has anyone encountered this issue before? Thanks!
UPDATE #2
I was able to resolve this (although I believe it is more of a workaround than a solution) by adding the following to my 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
The Measurement data coming in was a QueryDict when I believe I needed a Dict. There were also some extra brackets around the key and values so I had to remove those as well.
Still seeking a better answer than this!