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.

Reply via email to