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

如何在Django测验中实现无重复的题目随机排序?

解决Django测验随机出题重复的问题

你遇到的重复问题根源在于每次请求都调用order_by('?')重新随机排序,而视图依赖user_answers.count()作为当前题目索引。两次请求的排序结果不同,会导致索引对应的题目重复或跳过。

解决方案:为每个用户的测试生成固定的随机题目顺序,并保存到UserTest模型中,后续所有请求都复用这个顺序。

1. 修改UserTest模型

添加字段存储随机排序的题目ID列表:

# models.py
from django.db import models
from django.contrib.auth.models import User

class UserTest(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    test_set = models.ForeignKey(TestSet, on_delete=models.CASCADE)
    random_question_order = models.JSONField(default=list)  # 存储随机排序的题目ID
    # 保留原有的其他字段

2. 调整视图逻辑

在创建UserTest时生成固定随机顺序,后续请求复用该顺序:

@login_required
def test(request, test_id):
    test_set = get_object_or_404(TestSet, id=test_id)
    user_test, created = UserTest.objects.get_or_create(user=request.user, test_set=test_set)
    
    # 首次创建测试时,生成并保存随机题目顺序
    if created:
        question_ids = list(test_set.question_set.values_list('id', flat=True))
        import random
        random.shuffle(question_ids)
        user_test.random_question_order = question_ids
        user_test.save()
    
    # 根据保存的顺序获取题目(保持固定排序)
    questions = test_set.question_set.filter(id__in=user_test.random_question_order).order_by(
        models.Case(
            *[models.When(id=q_id, then=pos) for pos, q_id in enumerate(user_test.random_question_order)]
        )
    )
    
    user_answers = user_test.useranswer_set.all()
    correct_answers = sum(user_answer.selected_answer.is_correct for user_answer in user_answers)
    current_question_index = user_answers.count()
    find_percent = int(int(correct_answers) / len(questions) * 100)

    num_questions = questions.count()
    if current_question_index < num_questions:
        # 从固定顺序中取当前题目
        current_question_id = user_test.random_question_order[current_question_index]
        current_question = test_set.question_set.get(id=current_question_id)
        
        if request.method == 'POST':
            form = QuestionForm(request.POST, question=current_question)
            if form.is_valid():
                user_answer = form.cleaned_data['selected_answer']
                user_test.useranswer_set.update_or_create(question=current_question,
                                                          defaults={'selected_answer': user_answer})
                return redirect('test', test_id=test_id)
        else:
            form = QuestionForm(question=current_question)
    else:
        return render(request, 'test_view.html', {'test_set': test_set, 'user_test': user_test, 'questions': questions,
                                                  'show_result': True, 'current_question': None,
                                                  'correct_answers': correct_answers, 'find_percent': find_percent})

    return render(request, 'test_view.html',
                  {'test_set': test_set, 'form': form, 'current_question_index': current_question_index,
                   'current_question': current_question, 'correct_answers': correct_answers})

原理说明

  • 首次启动测试时,生成一次随机题目ID序列并持久化到UserTest中,确保每个用户的测试顺序固定。
  • 后续请求通过id__in和Case/When保持题目顺序与保存的序列一致,避免重复排序导致的题目重复。
  • 用保存的序列索引获取当前题目,保证进度逻辑稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:55:12