How to save a modelSerializer that has relations? - django

1.2k views Asked by At

I want to save a sent json data to db by django-rest-framework. the problem is, not saving the relation and returns error.

The bellow snippet is my models:

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', on_delete=models.CASCADE)
    name = models.CharField(max_length=30)
    family = models.CharField(max_length=50)

class Klass(models.Model):
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=500)
    teacher = models.ForeignKey(Profile, related_name='teacher', on_delete=models.CASCADE)

I use below serializer for serializing/deserializing the Klass model.

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ('pk', 'name', 'family')

class KlassSerializer(serializers.ModelSerializer):
    teacher = ProfileSerializer()        

    class Meta:
        model = Klass
        fields = ('id', 'title', 'description', 'teacher')

now when I prepare a JSON object and send it to the view, it returns error. the below is the view class:

class KlassView(APIView):
"""for SELECT, INSERT Queries"""

    def get(self, request, pk):
         # somthing

    @csrf_exempt
    def post(self,request, pk=None):
        """For Creating A Class"""
        serializer = KlassSerializer(data=request.data)
        if serializer.is_valid():
            teacher = ProfileSerializer(request.data['teacher']['pk'])
            serializer.teacher = teacher.data            
            serializer.save()
            return Response({'data': serializer.data})
        else:
            return Response({'data': serializer.errors})

and the error is:

The .create() method does not support writable nested fields by default. Write an explicit .create() method for serializer mainp.serializers.KlassSerializer, or set read_only=True on nested serializer fields.

How can I save relation in KlassSerializer in order to save to db?

2

There are 2 answers

2
Hosein Remezan On BEST ANSWER

At first change your serializer like below:

class KlassSerializer(serializers.ModelSerializer):
    # teacher = ProfileSerializer() # No need to this!

    class Meta:
        model = Klass
        # fields = ('id', 'title', 'description', 'teacher')
        fields = ('id', 'title', 'description') # Omit teacher

Then get profile from requested user and pass it to your serializer:

    def post(self,request, pk=None):
    """For Creating A Class"""
    serializer = KlassSerializer(data=request.data)
    if serializer.is_valid():
        teacher = ProfileSerializer(request.data['teacher']['pk'])
        serializer.teacher = teacher.data            
        serializer.save(teacher=request.user.profile) # Retrieve teacher and stroe 
        return Response({'data': serializer.data})
    else:
        return Response({'data': serializer.errors})
1
Avinash Raj On

Just override the create method of ModelSerializer in KlassSerializer.

class KlassSerializer(serializers.ModelSerializer):
    teacher = ProfileSerializer()        

    class Meta:
        model = Klass
        fields = ('id', 'title', 'description', 'teacher')

    def create(self, validated_data):
        profile = Profile.objects.filter(pk=validated_data['teacher']['pk'])
        if profile:
            k = Klass()
            k.teacher = profile
            ...