Django考试表单提交遇TypeError及数据存储问题求助
解决考试表单提交的TypeError问题并完善数据存储逻辑
嗨,我来帮你搞定这个问题!首先看你遇到的TypeError at /students/exam/1/ int() argument must be a string, a bytes-like object or a number, not 'list'错误,根源很明显:
你用request.POST.getlist('question_pk')拿到的是所有问题ID的列表,但接下来直接int(question_pk)试图把整个列表转成整数,这肯定行不通。下面一步步解决:
第一步:修复TypeError错误
核心修改点:
- 正确查询问题对象:不需要把列表转成单个整数,直接用Django的
__in查询条件匹配所有问题ID:question_pk = request.POST.getlist('question_pk') # 用__in匹配列表里的所有ID,Django会自动处理类型转换 question_obj = Question.objects.filter(id__in=question_pk) - 修正选项ID的获取逻辑:原来的循环
question_obj会导致变量名混淆,表单里的选项name是choice_pk{问题ID},所以直接循环question_pk里的ID来获取对应选项更合理:choice_pk = [request.POST[f'choice_pk{q}'] for q in question_pk]
第二步:完善答题数据的存储逻辑
接下来帮你把答题结果完整存入数据库,结合你注释里的TakenQuiz模型推测,我们实现完整的保存逻辑:
修改后的完整视图函数
@login_required @student_required def take_exam(request, pk): course = get_object_or_404(Course, pk=pk) student = request.user.student # 用all()更清晰,filter()无参数等价于all() questions = course.questions.all() total_questions = questions.count() marks_obtainable = Details.objects.get(course_id=course) # 初始化得分 total_obtained_marks = 0 # 每题分值(假设总分除以题数,可根据实际需求调整) per_question_mark = marks_obtainable.maximum_marks / total_questions if request.method == 'POST': question_pk = request.POST.getlist('question_pk') question_obj = Question.objects.filter(id__in=question_pk) choice_pk = [request.POST[f'choice_pk{q}'] for q in question_pk] zipped = zip(question_obj, choice_pk) # 准备批量创建的记录,提升性能 taken_quiz_records = [] for question, selected_choice_id in zipped: # 获取当前问题的正确答案 correct_answer = question.answers.filter(is_correct=True).first() is_correct = False if correct_answer and int(selected_choice_id) == correct_answer.id: is_correct = True total_obtained_marks += per_question_mark print(f"Question {question.id} answered correctly!") else: print(f"Question {question.id} answered incorrectly.") # 构造答题记录对象(先暂存,最后批量保存) taken_quiz_records.append( TakenQuiz( student=student, course=course, question=question, selected_choice_id=selected_choice_id, is_correct=is_correct ) ) # 批量保存所有答题记录,比逐个save()更高效 TakenQuiz.objects.bulk_create(taken_quiz_records) # 更新Details中的实际得分(如果业务需要) marks_obtainable.marks_obtained = total_obtained_marks marks_obtainable.save() # 可添加提交成功后的跳转,比如转到考试结果页 # return redirect('exam_result', pk=pk) return render(request, 'classroom/students/take_exam_form.html', { 'course': course, 'questions': questions, # 变量名改成复数更清晰 'total_questions': total_questions, 'marks_obtainable': marks_obtainable })
模板小优化(避免变量名混淆)
把模板里的循环变量改得更清晰,避免上下文变量冲突:
<h2 class="mb-3">{{ course.name }}</h2> Course id <h2 class="mb-3">{{ course.id }}</h2> Student id <h2 class="mb-3">{{ request.user.id }}</h2> Total Question: <h2 class="mb-3">{{ total_questions }}</h2> Mark Obtainable <h2 class="mb-3">{{ marks_obtainable.maximum_marks }}</h2> <form method="post" novalidate> {% csrf_token %} {% for q in questions %} <input type="hidden" name="question_pk" value="{{ q.pk }}"> <h3 class="text-info">{{ q.text|safe }}</h3> {% for choice in q.answers.all %} <input class="form-check-input" type="radio" name="choice_pk{{ q.pk }}" id="choices-{{ forloop.parentloop.counter }}-{{ forloop.counter }}" value="{{ choice.pk }}"> <label class="form-check-label" for="choices-{{ forloop.parentloop.counter }}-{{ forloop.counter }}"> {{ choice.text|safe }} </label> {% endfor %} {% endfor %} <button type="submit" class="btn btn-primary">Submit Now →</button> </form>
关键说明
- 批量创建记录:用
bulk_create比循环逐个save()更高效,适合批量数据插入场景。 - 得分计算:这里假设每题分值为总分除以题数,你可以根据实际业务调整(比如不同题目设置不同分值)。
- 容错处理:增加了
correct_answer的判空逻辑,避免因问题未设置正确答案而抛出错误。
内容的提问来源于stack exchange,提问作者Olaniyan Adewale
相关产品推荐
相关产品推荐

