After spending a week re-reading the docs, digging into the source, searching this forum, and testing and tracing with pdb, I decided it is time to ask for help. I finally feel like I have isolated what I don't understand about the DRF and implementing a flexible way to write to my nested serializer. Reads are working great, but I want to use the same nested JSON (returned by the read), as my write schema.
I have tried a variety of ideas from the forum, (like this <https://groups.google.com/forum/#!topic/django-rest-framework/XBJztipJsYE>, this <https://groups.google.com/forum/?fromgroups#!searchin/django-rest-framework/nested$20deserialization%7Csort:relevance/django-rest-framework/yawfuIsl5gE/ND7wXqgeCc4J>, and this <https://medium.com/django-rest-framework/dealing-with-unique-constraints-in-nested-serializers-dade33b831d9>) with varying levels of partial success. Let's use a generic example (since my code is a mess) and it is easier for others to associate with: #models.py class Color(models.Model): name = models.CharField(max_length=100, unique=True) finish = models.CharField(max_length=100, null=True, blank=True) class Car(models.Model): make = models.CharField(max_length=100, unique=True) model = models.CharField(max_length=100, unique=True) color = models.ForeignKey(Color) #serializer.py class CarSerializer(serializers.ModelSerializer): class Meta: model = models.Color fields = ('name', 'finish') class CarSerializer(serializers.ModelSerializer): color = ColorSerializer() class Meta: model = models.Car fields = ('make', 'model', 'color') #data to write car_data = { 'make': 'Dodge', 'model': 'Daytona', 'color': {'name': 'black', 'finish': 'gloss'} } # instantiate a serializer with the data to write mycar = serializers.CarSerializer(data=car_data) # runs the to_internal_value, and validation methods on the fields specified mycar.is_valid() # Assuming the data is valid, this writes the instance to the database mycar.save() Goal: Create a new car and specify its color, IF the color exists, it should simply return the existing object, ELSE create the new Color object, and return it. At a high level, the logic seems simple, but translating this to the serializer logic has been difficult. I am clearly not the only one who does this based on the number of questions in the forum related to writable nested serializers. So rather than seeking a solution, I am looking to understand the building blocks involved in validating data, creating nested objects, and saving the final result. Apologies if this is explained elsewhere, but I think I have researched as much as I could and still cannot quite understand how it all works. The following questions are meant to clear up my confusion (and likely others are scratching their heads). Perhaps we can create a section in the docs or a tutorial on writable nested deserialization: 1) When the parent serializer mycar.is_valid() is called, it appears to follow the nested relationship, and validates the color.to_internal_value(). - So the validation process appears to automatically follow the nested relationship, which I would assume would continue (perhaps the nested depth was 5). - The confusion is for validation or data manipulation, I would specify the to_internal_value or validate methods under each serializer class. This is good as it keeps the logic under the serializer class. 2) In the docs <http://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields>, it states, "If you want to implement a read-write relational field, you must also implement the .to_internal_value(self, data) method." - I don't really understand what to do in the to_internal_value() method. - The examples I have seen use it for a variety of things, but it is not clear if this is meant strictly for validation. - Would it be used to access the self.Meta.model manager in the Color serializer, to lookup an existing Color object, and return the instance to the parent. 3) The validation automatically occurs for the nested data, by drilling down into each serializer class, but I found the create method DOES NOT appear to follow the relationship. - When it comes to saving the validated data, the create() method is called for the serializer associated to the parent Car object. - To handle the nested create, it seems this all needs to be done from the parent (Car) serializer; using the model manager methods (.get(), .create(), etc), for BOTH the Car and Color objects. - Why can't the parent serializer (Car) see that a nested relationship exists, and call the nested create method? - It seems cleaner to have the child Color.create() handle the lookup for existing or create new (Color.objects.get_or_create), and return the instance. - Then the parent Car serializer create can finish creating the Car object with the instance returned from the Color serializer. - This way each serializer locally handles the validation, lookup, and creation. - If the nested depth is 5, the serializer at level1 would have a really complicated create() method. 4) ModelSerializer is nice for simple models like the example, so why would I want to convert it to a Serializer? - I have read Tom mention mention many times to re-write the ModelSerializer as a Serializer, but I want to understand the real differences with ModelSerializer vs Serializer. Thanks in advance, Jason -- You received this message because you are subscribed to the Google Groups "Django REST framework" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
