从 Django 休息框架中的 ManytoMany 字段获取 None 类型值
Getting None type value from ManytoMany Field in django rest framework
我无法在序列化程序列表的 ManytoMany 字段中检索答案选择 ID 或检索
相反,我得到了 quiz.Choice.None
我明白为什么会这样,但是如果我从序列化程序中删除 answer = serializers.CharField()
这一行。创建问题时引发错误:
{
"answer": [
"Incorrect type. Expected pk value, received str."
]
}
我无法从前端传递答案,我希望检索 "answer": [2,3]
而不是 None 并且我也知道如果我从序列化程序中删除 answer = serializers.CharField()
这一行。它解决了这个问题,但它提出了另一个问题,我无法传递一个甚至尚未创建的答案选择 ID。此类问题的最佳解决方案是什么?我还尝试对空数组进行答案验证。但这甚至不起作用。
{
"id": 5,
"label": "Question 1",
"answer": "quiz.Choice.None",
"explanation": "New Added fhfd",
"mode": 1,
"subtopic": 2,
"choice": [
{
"id": 5,
"option": "option 6 Edited New One",
"question": 5
},
{
"id": 6,
"option": "option 5 Hllloo Sakib",
"question": 5
}
]
}
我的模特:
# Question Mode
MODE = ((0, "Easy"), (1, "Medium"), (2, "Hard"))
class Question(models.Model):
"""Question Model"""
label = models.CharField(max_length=1024)
answer = models.ManyToManyField("Choice", related_name="quesans", blank=True)
explanation = models.TextField(blank=True)
mode = models.IntegerField(choices=MODE, default=0)
subtopic = models.ForeignKey(
"motherset.Subtopic", on_delete=models.CASCADE, related_name="question"
)
created_time = models.DateTimeField(auto_now_add=True, blank=True)
def __str__(self):
return self.label
class Choice(models.Model):
"""Question Option"""
option = models.CharField(max_length=1024)
question = models.ForeignKey(
Question, on_delete=models.CASCADE, related_name="choice", blank=True, null=True
)
def __str__(self):
return self.option
在 Serializers.py:
class ChoiceSerializer(serializers.ModelSerializer):
"""Serializers for Question Choice"""
id = serializers.IntegerField()
class Meta:
model = Choice
fields = ("id", "option", "question")
class CreateQuestionSerializer(serializers.ModelSerializer):
choice = ChoiceSerializer(many=True, partial=True)
answer = serializers.CharField()
class Meta:
model = Question
fields = ("id", "label", "answer", "explanation", "mode", "subtopic", "choice")
extra_kwargs = {"answer": {"validators": []}}
def create(self, validated_data):
"""Create Model With nested Serializer"""
choices_data = validated_data.pop("choice")
answerString = validated_data.pop("answer", [])
answer = literal_eval(answerString)
print(answer)
print(type(answer))
question = Question.objects.create(**validated_data)
for choice_data in choices_data:
choice_created = Choice.objects.create(
option=choice_data["option"], question=question
)
for choice_option in answer:
if choice_option == choice_created.option:
question.answer.add(choice_created)
question.save()
return question
def update(self, instance, validated_data):
"""Update Instance including nested serializer"""
choices_data = validated_data.pop("choice", None)
if choices_data is not None:
for choice_data in choices_data:
choice = Choice.objects.get(pk=choice_data["id"])
choice.option = choice_data["option"]
choice.save()
return super().update(instance, validated_data)
在 api.py 中:
class CreateQuestionView(viewsets.ModelViewSet):
serializer_class = CreateQuestionSerializer
queryset = Question.objects.all()
在 axios post 正文中:
{
"label": "Label q",
"explanation": "",
"answer": ["option 7","option 8"],
"mode": 1,
"subtopic": 2,
"choice": [
{
"id":3324242,
"option": "option 7"
},
{
"id":3324245,
"option": "option 8"
},
{
"id":3324248,
"option": "option 9"
}
]
}
answer
由其 pk
引用,而不是 option
。
像下面这样的调用应该有效,您可以在其中提交选择的 PK 而不是选项文本:
{
"label": "Label q",
"explanation": "",
"answer": [7, 8],
"mode": 1,
"subtopic": 2,
"choice": [
{
"id":3324242,
"option": "option 7"
},
{
"id":3324245,
"option": "option 8"
},
{
"id":3324248,
"option": "option 9"
}
]
}
更新
我将 Modelviewset class 更新为:
class CreateQuestionView(viewsets.ModelViewSet):
serializer_class = CreateQuestionSerializer
queryset = Question.objects.all()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
answer = []
for ans in instance.answer.all():
answer.append(ans.id)
newDict = {}
newDict.update(serializer.data)
newDict.update({"answer": answer})
return Response(newDict)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
newList = []
for question in serializer.data:
q = Question.objects.get(pk=question["id"])
answer = []
for ans in q.answer.all():
answer.append(ans.id)
newDict = {}
newDict.update(question)
newDict.update({"answer": answer})
newList.append(newDict)
return Response(newList)
现在一切正常。感谢我自己。 :v
我无法在序列化程序列表的 ManytoMany 字段中检索答案选择 ID 或检索
相反,我得到了 quiz.Choice.None
我明白为什么会这样,但是如果我从序列化程序中删除 answer = serializers.CharField()
这一行。创建问题时引发错误:
{
"answer": [
"Incorrect type. Expected pk value, received str."
]
}
我无法从前端传递答案,我希望检索 "answer": [2,3]
而不是 None 并且我也知道如果我从序列化程序中删除 answer = serializers.CharField()
这一行。它解决了这个问题,但它提出了另一个问题,我无法传递一个甚至尚未创建的答案选择 ID。此类问题的最佳解决方案是什么?我还尝试对空数组进行答案验证。但这甚至不起作用。
{
"id": 5,
"label": "Question 1",
"answer": "quiz.Choice.None",
"explanation": "New Added fhfd",
"mode": 1,
"subtopic": 2,
"choice": [
{
"id": 5,
"option": "option 6 Edited New One",
"question": 5
},
{
"id": 6,
"option": "option 5 Hllloo Sakib",
"question": 5
}
]
}
我的模特:
# Question Mode
MODE = ((0, "Easy"), (1, "Medium"), (2, "Hard"))
class Question(models.Model):
"""Question Model"""
label = models.CharField(max_length=1024)
answer = models.ManyToManyField("Choice", related_name="quesans", blank=True)
explanation = models.TextField(blank=True)
mode = models.IntegerField(choices=MODE, default=0)
subtopic = models.ForeignKey(
"motherset.Subtopic", on_delete=models.CASCADE, related_name="question"
)
created_time = models.DateTimeField(auto_now_add=True, blank=True)
def __str__(self):
return self.label
class Choice(models.Model):
"""Question Option"""
option = models.CharField(max_length=1024)
question = models.ForeignKey(
Question, on_delete=models.CASCADE, related_name="choice", blank=True, null=True
)
def __str__(self):
return self.option
在 Serializers.py:
class ChoiceSerializer(serializers.ModelSerializer):
"""Serializers for Question Choice"""
id = serializers.IntegerField()
class Meta:
model = Choice
fields = ("id", "option", "question")
class CreateQuestionSerializer(serializers.ModelSerializer):
choice = ChoiceSerializer(many=True, partial=True)
answer = serializers.CharField()
class Meta:
model = Question
fields = ("id", "label", "answer", "explanation", "mode", "subtopic", "choice")
extra_kwargs = {"answer": {"validators": []}}
def create(self, validated_data):
"""Create Model With nested Serializer"""
choices_data = validated_data.pop("choice")
answerString = validated_data.pop("answer", [])
answer = literal_eval(answerString)
print(answer)
print(type(answer))
question = Question.objects.create(**validated_data)
for choice_data in choices_data:
choice_created = Choice.objects.create(
option=choice_data["option"], question=question
)
for choice_option in answer:
if choice_option == choice_created.option:
question.answer.add(choice_created)
question.save()
return question
def update(self, instance, validated_data):
"""Update Instance including nested serializer"""
choices_data = validated_data.pop("choice", None)
if choices_data is not None:
for choice_data in choices_data:
choice = Choice.objects.get(pk=choice_data["id"])
choice.option = choice_data["option"]
choice.save()
return super().update(instance, validated_data)
在 api.py 中:
class CreateQuestionView(viewsets.ModelViewSet):
serializer_class = CreateQuestionSerializer
queryset = Question.objects.all()
在 axios post 正文中:
{
"label": "Label q",
"explanation": "",
"answer": ["option 7","option 8"],
"mode": 1,
"subtopic": 2,
"choice": [
{
"id":3324242,
"option": "option 7"
},
{
"id":3324245,
"option": "option 8"
},
{
"id":3324248,
"option": "option 9"
}
]
}
answer
由其 pk
引用,而不是 option
。
像下面这样的调用应该有效,您可以在其中提交选择的 PK 而不是选项文本:
{
"label": "Label q",
"explanation": "",
"answer": [7, 8],
"mode": 1,
"subtopic": 2,
"choice": [
{
"id":3324242,
"option": "option 7"
},
{
"id":3324245,
"option": "option 8"
},
{
"id":3324248,
"option": "option 9"
}
]
}
更新
我将 Modelviewset class 更新为:
class CreateQuestionView(viewsets.ModelViewSet):
serializer_class = CreateQuestionSerializer
queryset = Question.objects.all()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
answer = []
for ans in instance.answer.all():
answer.append(ans.id)
newDict = {}
newDict.update(serializer.data)
newDict.update({"answer": answer})
return Response(newDict)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
newList = []
for question in serializer.data:
q = Question.objects.get(pk=question["id"])
answer = []
for ans in q.answer.all():
answer.append(ans.id)
newDict = {}
newDict.update(question)
newDict.update({"answer": answer})
newList.append(newDict)
return Response(newList)
现在一切正常。感谢我自己。 :v