Home > database >  Django Rest Framework invalid serializer data, can not figure out why
Django Rest Framework invalid serializer data, can not figure out why

Time:08-16

I am creating a simple model with a many-to-many field. The model works fine and I can create model through the admin panel, and I can make a get request to see that model (except that it only returns user IDs instead of the user models/objects). My problem is when creating a post request to create said model.

I get one of the two errors depending on the changes I make, The serializer field might be named incorrectly and not match any attribute or key on the 'str' instance. or AssertionError: You cannot call '.save()' on a serializer with invalid data., either way it has something to do with my serializer. The following is my model,

class Schema(models.Model):
    week = models.PositiveIntegerField(primary_key=True, 
                                       unique=True,
                                       validators=[MinValueValidator(1), MaxValueValidator(53)],
                                       )
    users = models.ManyToManyField(MyUser, related_name="users")

    class Meta:
        ordering = ('week',)

My View,

class SchemaView(APIView):
    permission_classes = (SchemaPermissions,)

    def get(self, request):
        schemas = Schema.objects.all()
        serializer = SchemaSerializer(schemas, many=True)

        return Response(serializer.data)

    def post(self, request):
        data = request.data
        serializer = SchemaSerializer(data=data)
        serializer.is_valid()
        serializer.save()
        return Response(serializer.data, status=status.HTTP_200_OK)

And my serializer,

class SchemaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Schema
        fields = ('week', 'users')

    def create(self, validated_data):
        users_data = validated_data.pop('users')
        users = MyUser.objects.filter(id__in=users_data)
        schema = Schema.objects.create(week=validated_data.week, users=users)

        return schema

    def update(self, instance, validated_data):
        users_data = validated_data.pop('users')
        users = MyUser.objects.filter(id__in=users_data)
        instance.users.clear()
        instance.users.add(*users)
        instance.saver()
        return instance

The idea is that if a week number already exists then it should call the update() function and then it should simply overwrite the users related to that week number, otherwise it should call create() and create a new week number with relations to the given users. The following is the result of printing the serializer after initializing it in the view.

SchemaSerializer(data={'week': 32, 'users': [1, 2, 3]}):
    week = IntegerField(max_value=53, min_value=1, validators=[<UniqueValidator(queryset=Schema.objects.all())>])
    users = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=MyUser.objects.all())

It seems to me that the serializer should be valid for the given model? I am perhaps missing some concepts and knowledge about Django and DRF here, so any help would be greatly appreciated!

CodePudding user response:

First you need set the field for saving users in the SchemaSerializer. And you don't need to customize the create and update method because the logic could be coded in the views.

class SchemaSerializer(serializers.ModelSerializer):
    users = UserSerializer(read_only = True, many = True)
    user_ids = serializers.ListField(
        child = serializers.IntegerField,
        write_only = True
    )

    class Meta:
        model = Schema
        fields = ('week', 'users', 'user_ids',)

    # remove create and update method

And in views.py,

class SchemaView(APIView):
    permission_classes = (SchemaPermissions,)

    def get(self, request):
        ...

    def post(self, request):
        data = request.data
        serializer = SchemaSerializer(data=data)
        if serializer.is_valid():
            input_data = serializer.validated_data
            week = input_data.get('week')
            user_ids = input_data.get('user_ids')
            if Schema.objects.filter(week = week).count() > 0:
                schema = Schema.objects.get(week = week).first()
            else:
                schema = Schema.objects.create(week = week)
            schema.users.set(user_ids)
            schema.save()
        
            return Response(SchemaSerializer(schema).data, status=status.HTTP_200_OK)
        else:
            print(serializer.errors)
            return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)

And of course, the payload data should be

{'week': 23, 'user_ids': [1,2,3]}
  • Related