Сериализатор Django возвращает пустой массив
У меня минимальный опыт работы с Python и нет опыта работы с Django, но мне поручили исправить ошибку в приложении Django.
У меня есть следующие модели
` 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`
и затем этот код для сериализации ответа на POST-запрос
` 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"]`
Тело моего сообщения выглядит следующим образом
` {
"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`
В возвращаемых json-данных есть все вопросы опроса, но для любого вопроса, который содержит множественный выбор "ответов" в сообщении, я получаю в ответ пустой массив (answers: []).
Я подозреваю, что проблема кроется в
def get_answers(self, obj): return obj.answers if obj.answers else []
кода, что obj.answers является null/empty, но я не уверен, почему.
Мои усилия по поиску в google пока ни к чему не привели - я думаю, что мне просто не хватает знаний о домене, чтобы понять его в достаточной степени. Аналогично chatgpt ни к чему не привел - опять же недостаток знаний о домене. Не знаю, дает ли chatgpt мусорный результат или нет, но ничего из того, что он предложил, до сих пор не сработало.
Я не уверен, почему ваш obj.answers
кажется пустым, но я вижу, что вы определили конкретный сериализатор для применения определенной обработки к этому конкретному атрибуту.
В этом случае вы можете напрямую определить сериализатор методов, используя serializers.SerializerMethodField()
в вашем основном сериализаторе, который будет автоматически указывать на ваш геттер для получения ответов. Возможно, упрощение сериализатора прояснит ситуацию.
Тогда вы можете добавить отладочную печать, чтобы предоставить нам значение, возвращаемое вашим сериализатором в этом случае.
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 является полем, доступным только для чтения.
Я исправил проблему, изменив
answers = serializers.SerializerMethodField(required=False)
до
answers = serializers.ListField(
child=serializers.CharField(max_length=100), required=False, allow_null=True
)