Django多题测验:PostgreSQL仅存首个选项,Pytest报302失败
多选项测验数据保存异常问题修复
问题现象
开发多选项测验功能时,PostgreSQL仅保存第一个选项,无论提交多少个选项和正确标记。POST数据显示提交了5个选项(第3、5个为正确),但表单cleaned_data仅返回[{'text': '99', 'is_correct': False}],最终仅该选项入库,同时Pytest测试返回302失败。
核心原因
表单初始化时仅从initial参数读取ans_count生成字段,POST提交时未根据提交的ans_count值动态生成对应数量的answer_*和is_correct_*字段,导致Django忽略了除初始1个字段外的所有动态提交数据。
修复方案
1. 修改forms.py,适配POST提交的ans_count值
在表单的__init__方法中,优先从POST数据读取ans_count,确保生成对应数量的字段:
class AddMultipleForm(forms.ModelForm): ans_count = forms.IntegerField(min_value=1, label="Number of Answers Anzahl der Antworten") class Meta: model = MultiQuesModel fields = ["question", "language_name"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 优先从POST数据取ans_count,没有则用initial或默认1 ans_count = int(self.data.get("ans_count", self.initial.get("ans_count", 1))) for i in range(ans_count): self.fields[f"answer_{i}"] = forms.CharField(max_length=200, required=True) self.fields[f"is_correct_{i}"] = forms.BooleanField( required=False, widget=forms.CheckboxInput(attrs={"class": "checkbox"}) ) def clean(self): cleaned_data = super().clean() ans_count = cleaned_data.get("ans_count") print(ans_count) answers = [] for i in range(ans_count): answer_text = cleaned_data.get(f"answer_{i}") is_correct = cleaned_data.get(f"is_correct_{i}") if answer_text: answers.append({"text": answer_text, "is_correct": is_correct}) if not answers: raise forms.ValidationError( "Please fill out at least one answer. Bitte füllen Sie mindestens eine Antwort aus." ) cleaned_data["answers"] = answers return cleaned_data
2. 修复HTML模板中的label错误
在multiformular.html中,修正重复的label标签:
<!-- 原错误代码 --> {{ form.question.label_tag }} {{ form.language_name }} <!-- 修改为 --> {{ form.language_name.label_tag }} {{ form.language_name }}
3. 验证视图逻辑(无需修改,确认即可)
views.py中的保存逻辑正确,确保表单验证通过后,遍历所有answers_data创建或获取Answer实例,并通过through_defaults设置正确标记:
# views.py中post方法的保存逻辑(无需修改) if form.is_valid(): instance = form.save(commit=False) instance.save() answers_data = form.cleaned_data["answers"] print(answers_data) for answer_data in answers_data: answer_text = answer_data["text"] is_correct = answer_data["is_correct"] answer, _ = Answer.objects.get_or_create(text=answer_text) instance.answers.add(answer, through_defaults={"is_correct": is_correct}) return redirect("success_page")
测试验证
修复后重新提交表单,检查cleaned_data是否包含所有提交的选项数据,确认数据库中正确保存所有选项及对应的is_correct标记,同时Pytest测试应返回正常响应(不再是302失败)。
内容的提问来源于stack exchange,提问作者Davidcopperfield
相关产品推荐
相关产品推荐

