Django Form动态传递Choice选项提交时报无效选择错误如何解决
报错根因
- 表单校验时的可选选项和你提交的选项所属题目不匹配:
你在get_context_data方法里提前将全局计数变量count+1,当用户提交上一道题的答案时,POST请求触发表单实例化,get_form_kwargs获取的是count自增后下一道题的选项列表,上一道题的选项id自然不在当前校验用的可选列表里,触发校验失败。 - 额外隐患:你使用类变量存储题目集合、计数
count,多用户同时访问时数据会互相覆盖,存在严重的逻辑错误。 - 小问题:你自定义的表单字段名为
answerss,但在form_valid里获取值的时候写的是answers,拼写错误会拿不到提交的id值。
修复步骤
- 调整计数变量的更新逻辑,不要在
get_context_data里提前自增,改为提交表单成功后再更新计数,同时把类变量改为存在用户session里,避免多用户串数据:
# 先删掉类里定义的question_collection、question_id_collection、count类变量 def get_context_data(self,*args,**kwargs) : context = super().get_context_data(*args,**kwargs) # 从session取当前计数,默认是0 current_count = self.request.session.get('quiz_count', 0) # 初始化题目集合到session,避免每次请求都查库 if 'question_id_collection' not in self.request.session: find = quizz.objects.get(category=formality.question_subject) ids = question.objects.filter(quiz_id = find.quiz_id) self.request.session['question_id_collection'] = [i.question_id.hex for i in ids] self.request.session['question_collection'] = [i.question for i in ids] question_id_collection = self.request.session['question_id_collection'] question_collection = self.request.session['question_collection'] context['data4'] = correctAnswer.objects.filter(question_id = question_id_collection[current_count]) context['data5'] = question.objects.filter(question = question_collection[current_count]).values('question_id') context['data6'] = correctAnswer.objects.filter(check_answer_bool = 1, question_id = question_collection[current_count]).values('correct_Answer_id') context['data2'] = current_count context['data3'] = question_collection[current_count] return context def get_form_kwargs(self, *args,**kwargs) : message = super(Start_Game,self).get_form_kwargs(*args,**kwargs) current_count = self.request.session.get('quiz_count', 0) question_id_collection = self.request.session['question_id_collection'] option_choice = [] q = correctAnswer.objects.filter(question_id = question_id_collection[current_count]).values_list('correct_Answer_id','answer') for item in q: option_choice.append((item[0].hex,item[1])) message['options'] = option_choice return message def form_valid(self, form) : current_count = self.request.session.get('quiz_count', 0) question_id_collection = self.request.session['question_id_collection'] question_collection = self.request.session['question_collection'] # 字段名是answerss,同时MultipleChoiceField提交的是数组,要用getlist print('selected id is ',self.request.POST.getlist('answerss')) obj = form.save(commit= False) obj.user_id = self.request.user # 外键赋值要传实例或者直接给_id传值,不能传values查询集 obj.question_id = question.objects.get(question = question_collection[current_count]) obj.correct_Answer_id = correctAnswer.objects.get(check_answer_bool = 1, question_id = question_id_collection[current_count]) obj.save() # 提交成功再更新计数 current_count +=1 if current_count >= len(question_id_collection): current_count = 0 self.request.session['quiz_count'] = current_count return super().form_valid(form)
- 如果你不需要校验
answerss字段的选项合法性,可以直接给字段加required=False或者在校验前动态更新choices,不过更推荐上面调整计数逻辑的方案,符合业务流程。
内容的提问来源于stack exchange,提问作者Divit Rao
相关产品推荐
相关产品推荐

