Django Rest Framework a writable nested serializer with multiple nested objects

I am trying to create a writable serializer. My parent model is Game, and nested models are Measurements. I am trying to publish this data in my DRF application using AJAX. However, when trying to publish data, nested dimensions 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 = 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 

My view for the game is as follows:

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

I followed this tutorial for this structure.

I am trying to publish 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){}) }); 

When I published this data in the create method in GameSerializer, I found that validate_data.pop ('dimensions') contains a list of 3 ordered dictionaries (OrderedDict ()) that are empty.

UPDATE: I found that the start_data entering through request.data is structured as follows:

 '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 problem before? Thanks!

UPDATE # 2

I managed to solve this problem (although I believe this is a workaround rather 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 accepted measurement data was QueryDict when I figured I needed a Dict. There were also some extra brackets around the key and values, so I also had to remove them.

Still looking for a better answer than that!

+5
source share
1 answer

The problem here is on the interface side. By default, the server interprets the data as application/x-www-form-urlencoded , and in order to understand that you are sending it json , you need to specify contentType in the $.ajax request:

 $.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){}); 

Now your validated_data.pop('measurements') method in create() your GameSerializer should provide three objects with your measurements (but remember to repeat the workaround from Update # 2).

0
source

Source: https://habr.com/ru/post/1243256/


All Articles