2

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'

Arjunsingh
  • 703
  • 9
  • 22

2 Answers2

1

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
Satendra
  • 6,755
  • 4
  • 26
  • 46
  • The above get_serializer_class works fine for retrieval, but for post it gives an error - Error in viewset is_valid() missing 1 required positional argument: 'self' Now if I change the code to this def get_serializer_class(self): if self.request.method == 'POST': return CommissionRulePOSTSerializer(data=self.request.data) return CommissionRuleRetrieveSerializer(data=self.request.data) The GET request gives this error - CommissionRulePOSTSerializer' object is not callable and it works for POST request – Arjunsingh May 06 '18 at 07:27
  • can you post your view class – Satendra May 06 '18 at 07:40
0

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)
Arjunsingh
  • 703
  • 9
  • 22