Django Rest Framework writable nested serializer with multiple nested objects

2024/11/17 6:41:10

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!

Answer

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

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

Now your validated_data.pop('measurements') in create() method of your GameSerializer should yield three objects with your measurements (but don't forget to redo your workaround from Update#2).

https://en.xdnf.cn/q/71577.html

Related Q&A

Django How to Serialize from ManyToManyField and List All

Im developing a mobile application backend with Django 1.9.1 I implemented the follower model and now I want to list all of the followers of a user but Im currently stuck to do that. I also use Django…

PyDrive and Google Drive - automate verification process?

Im trying to use PyDrive to upload files to Google Drive using a local Python script which I want to automate so it can run every day via a cron job. Ive stored the client OAuth ID and secret for the G…

Using rm * (wildcard) in envoy: No such file or directory

Im using Python and Envoy. I need to delete all files in a directory. Apart from some files, the directory is empty. In a terminal this would be:rm /tmp/my_silly_directory/*Common sense dictates that i…

cant import django model into celery task

i have the following task:from __future__ import absolute_importfrom myproject.celery import appfrom myapp.models import Entity@app.task def add(entity_id):entity = Entity.objects.get(pk=entity_id)retu…

Running unit tests with Nose inside a Python environment such as Autodesk Maya?

Id like to start creating unit tests for my Maya scripts. These scripts must be run inside the Maya environment and rely on the maya.cmds module namespace.How can I run Nose tests from inside a runnin…

Python Newline \n not working in jupyter notebooks

Im trying to display the tuples of a postgreSQL table neatly in my Jupyter Notebook, but the newline \n escape character doesnt seem to work here (it works for my python scripts w/ same code outside of…

Dynamically calling functions - Python

I have a list of functions... e.g.def filter_bunnies(pets): ...def filter_turtles(pets): ...def filter_narwhals(pets): ...Is there a way to call these functions by using a string representing their nam…

py2exe windows service problem

I have successfully converted my python project to a service. When using the usual options of install and start/stop, everything works correctly. However, I wish to compile the project using py2exe, …

Draw a cumulative chart from a pandas dataframe?

I have a dataframe as follows:df = pd.DataFrame({cost_saving: [10, 10, 20, 40, 60, 60],id: [a, b, c, d, e, f]})How can I draw a cumulative chart of the savings?Im thinking of a line chart with number …

Sort a complex Python dictionary by just one of its values

I am writing a little optimization tool for purchasing stamps at the post office.In the process I am using a dictionary, which I am sorting according to what I learned in this other "famous" …