Django serializer returning empty array

I have minimal experience with Python, and no experience with Django, but I have been tasked with fixing a bug in a Django app.

I have the following models

`   class SurveyResponse(models.Model):
    survey = models.ForeignKey(to=Survey, on_delete=models.CASCADE, related_name="responses")
    # Don't want to clear out surveys if the mission is cleared. Still may be valuable
    mission_run = models.ForeignKey(to=MissionRun, on_delete=models.SET_NULL, blank=True, null=True,
                                    related_name="survey_responses")
    grade = models.CharField(max_length=15, blank=True, null=True)  # grade level
    gender = models.CharField(max_length=15, blank=True, null=True)  # gender selection
    race = models.CharField(max_length=50, blank=True, null=True)  # race selection
    exported_survey_file = models.ForeignKey(to="SurveyVendorFile", null=True, blank=True, on_delete=models.SET_NULL,
                                             related_name="survey_responses")
    exported_evaluator_file = models.ForeignKey(to="EvaluatorFile", null=True, blank=True, on_delete=models.SET_NULL,
                                                related_name="survey_responses")



class SurveyResponseAnswer(models.Model):
    survey_response = models.ForeignKey(to=SurveyResponse, on_delete=models.CASCADE, related_name="answers")
    survey_question = models.ForeignKey(to=SurveyQuestion, on_delete=models.CASCADE, related_name="answers")
    answers = ArrayField(models.CharField(max_length=100), null=True, blank=True)
    answer = models.CharField(max_length=100, null=True, blank=True)

    @property
    def reverse_coding(self):
        return self.survey_question.reverse_coding`

and then this code to serialize a response to a POST request

`   class SurveyResponseViewSet(mixins.CreateModelMixin, GenericViewSet):
    queryset = app_models.SurveyResponse.objects.all()
    permission_classes = []
    serializer_class = app_serializers.SurveyResponseCreateSerializer
    
    
class SurveyResponseAnswerCreateSerializer(serializers.ModelSerializer):
    survey_question_id = serializers.IntegerField()
    answers = serializers.SerializerMethodField(required=False)

    def get_answers(self, obj):
        return obj.answers if obj.answers else []

    class Meta:
        model = app_models.SurveyResponseAnswer
        exclude = ["survey_response", "survey_question"]


class SurveyResponseCreateSerializer(serializers.ModelSerializer):
    survey_id = serializers.IntegerField()
    answers = SurveyResponseAnswerCreateSerializer(many=True)
    mission_run_id = serializers.IntegerField()

    def create(self, validated_data):
        answers = validated_data.pop("answers", [])
        survey_response = app_models.SurveyResponse.objects.create(**validated_data)
        for answer in answers:
            app_models.SurveyResponseAnswer.objects.create(survey_response=survey_response, **answer)
        return survey_response

    class Meta:
        model = app_models.SurveyResponse
        exclude = ["survey", "mission_run"]`

My post body looks like this

`   {
    "missionRunId": 22,
    "surveyId": 2,
    "answers": [
        {
            "surveyQuestionId": 40,
            "answer": "1",
            "answers": []
        },
        {
            "surveyQuestionId": 41,
            "answer": null,
            "answers": [
                "1",
                "4",
                "3",
                "5"
            ]
        },
        {
            "surveyQuestionId": 43,
            "answer": null,
            "answers": [
                "a",
                "b"
            ]
        }, ... etc`

The returned json data has all the survey questions, but for any question which contains a multiple choice "answers" in the post, I get back a empty array (answers: []) in the response.

I suspect the issue lies in the def get_answers(self, obj): return obj.answers if obj.answers else [] code, that obj.answers is null/empty, but I am not sure why.

My google efforts so far have led me no where - I think I just lack the domain knowledge to understand it sufficiently. Likewise chatgpt has led me nowhere - again lack of domain knowledge I believe, I don't know if chatgpt is giving me garbage output or not, but nothing it has suggested has worked so far.

I'm not sure why your obj.answers appears to be empty, but I see that you have defined a specific serializer to apply a particular treatment to this specific attribute.

In this case, you can directly define a method serializer using serializers.SerializerMethodField() in your main serializer, which will automatically point to your getter for answers. Maybe simplifying the serializer will make things clearer.

Then you can add a debug print for give us the value returned by your serializer in this case.

class SurveyResponseCreateSerializer(serializers.ModelSerializer):
    survey_id = serializers.IntegerField()
    answers = serializers.SerializerMethodField()
    mission_run_id = serializers.IntegerField()

    @staticmethod
    def get_answers(obj):
        print(f"Debugging {obj.answers}")
        return obj.answers if obj.answers else []

    def create(self, validated_data):
        answers = validated_data.pop("answers", [])
        survey_response = app_models.SurveyResponse.objects.create(**validated_data)
        for answer in answers:
           app_models.SurveyResponseAnswer.objects.create(survey_response=survey_response, **answer)
        return survey_response

    class Meta:
        model = app_models.SurveyResponse
        exclude = ["survey", "mission_run"]`

SerializerMethodField is a readonly field.

I fixed the issue by changing

answers = serializers.SerializerMethodField(required=False)

to

answers = serializers.ListField(
    child=serializers.CharField(max_length=100), required=False, allow_null=True
)
Back to Top