Serializing custom related field in DRF
<p>I am trying to make a serializer with a nested "many to many" relationship. The goal is to get a serialized JSON object contain an array of serialized related objects. The models look like this (names changed, structure preserved)</p>

<pre>
from django.contrib.auth.models import User

PizzaTopping(models.Model):
    name = models.CharField(max_length=255)
    inventor = models.ForeignKey(User)

Pizza(models.Model):
    name = models.CharField(max_length=255)
    toppings = models.ManyToManyField(PizzaTopping)
</pre>

<p>The incoming JSON looks like this </p>

<pre>
{
  "name": "My Pizza",
  "toppings": [
    {"name": "cheese", "inventor": "bob"},
    {"name": "tomatoes", "inventor": "alice"}
  ]
}
</pre>

<p>My current serializer code looks like this</p>

<pre>
class ToppingRelatedField(RelatedField):
    def get_queryset(self):
        return Topping.objects.all()

    def to_representation(self, instance):
        return {'name': instance.name, 'inventor': instance.inventor.username}

    def to_internal_value(self, data):
        name = data.get('name', None)
        inventor = data.get('inventor', None)
        try:
            user = User.objects.get(username=inventor)
        except Setting.DoesNotExist:
            raise serializers.ValidationError('bad inventor')
        return Topping(name=name, inventor=user)

class PizzaSerializer(ModelSerializer):
    toppings = ToppingRelatedField(many=True)

    class Meta:
        model = Pizza
        fields = ('name', 'toppings')
</pre>

<p>It seems that since I defined the to_internal_value() for the custom field, it should create/update the many-to-many field automatically. But when I try to create pizzas, I get "Cannot add "": the value for field "pizzatopping" is None" ValueError. It looks like somewhere deep inside, Django decided that the many to many field should be called by the model name. How do I convince it otherwise?</p>

<p>Edit #1: It seems that this might be a genuine bug somewhere in Django or DRF. DRF seems to be doing the right thing, it detects that it is dealing with a ManyToMany field and tries to create toppings from the data using the custom field and add them to the pizza. Since it only has a pizza instance and a field name, it uses <code>setattr(pizza, 'toppings', toppings)</code> to do it. Django seems to be doing the right thing. The <code>__set__</code> is defined and seems to figure out that it needs to use add() method in the manager. But somewhere along the way, the field name 'toppings' gets lost and replaced by the default. Which is "related model name in lower case".</p>

<p>Edit #2: I have found a solution. I will document it in an answer once I am allowed. It seems that the <code>to_internal_value()</code> method in the <code>RelatedField</code> subclass needs to return a saved instance of a Topping for the ManyToMany thing to work properly. The existing docs show the opposite, a this link (<a href="http://www.django-rest-framework.org/api-guide/fields/#custom-fields" rel="nofollow">http://www.django-rest-framework.org/api-guide/fields/#custom-fields</a>) the example clearly returns an unsaved instance.</p>

<p>Seems like there is an undocumented requirement. For write operations to work with a custom ManyToMany field, the custom field class <code>to_internal_value()</code> method needs to save the instance before returning it. The DRF docs omit this and the example of making a custom field (at <a href="http://www.django-rest-framework.org/api-guide/fields/#custom-fields" rel="nofollow">http://www.django-rest-framework.org/api-guide/fields/#custom-fields</a>) shows the method returning an unsaved instance. I am going to update the issue I opened with the DRF team.</p>

python json django serialization django-rest-framework