You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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错误

核心修改点:

  1. 正确查询问题对象:不需要把列表转成单个整数,直接用Django的__in查询条件匹配所有问题ID:
    question_pk = request.POST.getlist('question_pk')
    # 用__in匹配列表里的所有ID,Django会自动处理类型转换
    question_obj = Question.objects.filter(id__in=question_pk)
    
  2. 修正选项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>

关键说明

  1. 批量创建记录:用bulk_create比循环逐个save()更高效,适合批量数据插入场景。
  2. 得分计算:这里假设每题分值为总分除以题数,你可以根据实际业务调整(比如不同题目设置不同分值)。
  3. 容错处理:增加了correct_answer的判空逻辑,避免因问题未设置正确答案而抛出错误。

内容的提问来源于stack exchange,提问作者Olaniyan Adewale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:40:12