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

Django在线测验系统二次启动后问题列表无法恢复的故障排查请求

帮你搞定Django测验重复触发错误的问题

嘿,我一眼就看出问题出在哪了——你在TakeQuizView里定义的questions是类属性,这意味着所有访问这个视图的请求都会共享同一个列表!

问题根源详解

当第一个用户完成测验后,self.questions里的元素已经被remove清空了。第二次再启动测验时,这个类属性还是空的,所以调用self.questions.remove(question)就会触发list.remove(x): x not in list错误。

你尝试添加的if index==1: self.questions=list(Question.objects.all())之所以没用,是因为类属性是全局共享的:如果有多个用户同时测验,或者你在测验过程中刷新页面,这个列表的状态会被打乱,甚至在第二步就被意外清空。

正确解决方案:用Session存储用户独立的测验状态

每个用户的测验进度应该是独立的,我们可以用Django的Session来存储每个用户的问题序列,这样就不会互相干扰了。修改后的代码如下:

urls.py(保持不变)

path('start',views.startquiz,name='start'),
path('test/<int:pk>/<int:index>',views.TakeQuizView.as_view(),name='test'),

views.py(重写核心逻辑)

def startquiz(request):
    # 获取所有问题ID,随机打乱顺序
    question_ids = list(Question.objects.values_list('id', flat=True))
    random.shuffle(question_ids)
    # 将打乱后的ID列表存入当前用户的session
    request.session['question_ids'] = question_ids
    
    if question_ids:
        # 跳转到第一个问题
        first_pk = question_ids[0]
        return redirect(reverse('quiz:test', args=(first_pk, 1)))
    else:
        # 没有问题时直接返回主页
        return redirect(reverse('quiz:main'))

class TakeQuizView(LoginRequiredMixin, View):
    def get(self, request, pk, index):
        # 从session获取当前用户的问题ID列表
        question_ids = request.session.get('question_ids', [])
        if not question_ids:
            # 没有测验数据时返回主页
            return redirect(reverse('quiz:main'))
        
        try:
            question = Question.objects.get(id=pk)
        except Question.DoesNotExist:
            return redirect(reverse('quiz:main'))
        
        ctx = {
            'question': question,
            'index': index,
            'n': len(question_ids)
        }
        return render(request, 'quiz/test.html', ctx)

    def post(self, request, pk, index):
        question_ids = request.session.get('question_ids', [])
        if not question_ids:
            return redirect(reverse('quiz:main'))
        
        total_questions = len(question_ids)
        # 移除当前已展示的问题ID
        if pk in question_ids:
            question_ids.remove(pk)
            request.session['question_ids'] = question_ids
        
        # 判断是否还有下一个问题
        if index < total_questions:
            if question_ids:
                next_pk = question_ids[0]
                return redirect(reverse('quiz:test', args=(next_pk, index + 1)))
            else:
                return redirect(reverse('quiz:main'))
        else:
            # 测验结束,清空session里的测验数据
            del request.session['question_ids']
            return redirect(reverse('quiz:main'))

方案优势

  1. 用户状态独立:每个用户的测验进度存在自己的Session中,不会和其他用户互相干扰
  2. 避免重复移除错误:即使刷新页面,Session里的状态会保留,不会重复执行remove操作
  3. 逻辑更健壮:处理了没有问题、问题不存在等异常场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:27:46