2
votes

In the serializer used to create a model I want to rename my model field to (field_name)_id so it's clearer for API consumers that this field is an ID field. The model also has a unique_together constraint on some fields. However when validation runs in the serializer, it fails with a KeyError that the field does not exist:

...rest_framework/utils/serializer_helpers.py", line 148, in __getitem__
    return self.fields[key]
KeyError: 'question'

Is there a simple way to get this to work? Minimal example code below.

Model

class MyModel(Model):
            question = ForeignKey('uppley.Question', null=False, on_delete=PROTECT)
            user = ForeignKey('catalystlab.User', null=False, on_delete=PROTECT)

            class Meta:
                unique_together = ('question', 'user',)

Serializer

        class MyCreateSerializer(ModelSerializer):

            question_id = PrimaryKeyRelatedField(
                write_only=True,
                source='question',
                queryset=Question.objects.all(),
            )

            user_id = PrimaryKeyRelatedField(
                write_only=True,
                source='user',
                queryset=User.objects.all(),
            )

            class Meta:
                model = MyModel
                fields = ('question_id', 'user_id',)

test.py - test for demonstration purposes

        question = QuestionFactory()
        user = UserFactory()

        data = {
            'question_id': question.id,
            'user_id': user.id,
        }
        serializer = MyCreateSerializer(data=data, write_only=True)
        is_valid = serializer.is_valid(raise_exception=True) #KeyError exception raised here.

Previously with DRF 3.10.3 this all worked fine, however with 3.11.0 this now throws a KeyError as mentioned above.

What I have tried

Removing the source field on PrimaryKeyRelatedField for user_id and question_id in the Serializer actually results in bypassing the unique_together validation in DRF and the KeyError is avoided. However the validated data is not mapped back to the original field names (user and question). In this case we have to manually change the keys back to their original names before we can create an instance of the Model from the validated data.

Is there a better way to do this?

1

1 Answers

1
votes

You can make a custom serializer like :-

class MyCreateSerializer(serializers.Serializer):

    question_id = serializers.PrimaryKeyRelatedField(
         write_only=True,
         queryset=Question.objects.all(),
    )

    user_id = PrimaryKeyRelatedField(
         write_only=True,
         queryset=User.objects.all(),
    )

and make custom create function in it for creating object. like :-

def create(self, validated_data):
    try:
        question = validated_data.get('question_id')
        user = validated_data.get('user_id')
        instance = MyModel.objects.create(question=question, user=user)
    except TypeError:
        raise TypeError("Something went wrong while creating objects")

    return instance