Arjunsingh
Arjunsingh

Reputation: 763

Django REST Framework ManyToMany Error

When I add a serializer for the ManyToMany Field, it displays the results on the REST API but when I post data then the serializer gives is_valid() as false. When I mention them as JSONFields, then the serializer is_valid() is True and the data gets saved, but upon viewing the api on localhost it gives the following error - 'Object of type 'ManyRelatedManager' is not JSON serializable'

class B(models.model):
    name = models.CharField()

class A(models.model):
    b = models.ManyToManyField(B)

class BSerializer(serializer.modelSerializer):
    class Meta:
        model=B
        fields = '__all__'

class ASerializer(serializer.ModelSerializer):
    b = BSerializer(many=true)

    def save(self):
        b_data = self.validated_data.pop('b')
        a = A.objects.create(**validated_data)
        b_instance = B.objects.get(name=b_data['name'])
        a.add(b_instance)

This gives perfect results on the REST Framework UI when hit with http://localhost:8000/a/REST but when I hit the POST request on postman with the data {'b':[{'name':'foo'}]} the serializer fails to is_valid() function.

But when I change the code to this:

class ASerializer(serializer.ModelSerializer):
    b = serializer.JSONField()

    def save(self):
        b_data = self.validated_data.pop('b')
        a = A.objects.create(**validated_data)
        b_instance = B.objects.get(name=b_data['name'])
        a.add(b_instance)

The postman hit saves the data for A and then adds the b instance to it. It is seen when I see the data in python shell. But upon viewing it on the REST Framework UI, it gives the follwoing error: 'Object of type 'ManyRelatedManager' is not JSON serializable'

Upvotes: 2

Views: 1094

Answers (2)

Arjunsingh
Arjunsingh

Reputation: 763

As answered by @Satendra I made 2 serializers but was receiving erros in viewset.

def create(self, request):
    try:
        serializer = self.get_serializer_class()
        if serializer.is_valid():
            serializer.save()
            return Response({"status": "success"})
        else:
            return Response({"status": "failure", "reason": 'Serializer not valid'})
    except Exception as e:
        print('Error in viewset', e)
        return Response({"status": "failure", "reason": e})

So just changed to this code and added a new line instantiating the serializer with data after calling the get_serializer_class and it works fine for both get and post request and using separate serializers for get and post

serializer = serializer(data=self.request.data)

Upvotes: 0

Satendra
Satendra

Reputation: 6865

You have to create two separate serializers

one for retrieval.

class A_RetriveSerializer(serializer.ModelSerializer):
    b = BSerializer(many=true)

    class Meta:
       model = A
       fields = '__all__'

and other for creating object.

class A_PostSerializer(serializer.ModelSerializer):
    b = serializer.JSONField()

    class Meta:
       model = A
       fields = ('b', )

    def save(self):
        b_data = self.validated_data.pop('b')
        a = A.objects.create(**validated_data)
        b_instance = B.objects.get(name=b_data['name'])
        a.b.add(b_instance)

and in your view override get_serializer_class method

def get_serializer_class(self):
    if self.request.method == 'POST':
       return A_PostSerializer
    return A_RetriveSerializer

Upvotes: 1

Related Questions