Python/Django中如何在GET和POST视图中使用同一随机生成的题目列表
问题解决方法
核心问题原因
当前代码每次触发trivia视图请求(不管是GET加载题目页,还是POST提交答案),都会重新执行随机抽样逻辑,两次拿到的题目子集完全不同,自然会出现答案和题目不匹配的问题。
方案一:使用Django Session存储抽题ID(推荐)
利用用户会话缓存本次随机抽取的题目ID列表,GET请求生成后存入服务端session,POST请求直接从session读取ID查询题目,无需重新随机抽题。服务端存储的ID用户无法篡改,可避免作弊问题。
修改后代码如下:
import random from django.shortcuts import render from .models import Trivia def trivia(request): if request.method == 'POST': # 从session读取之前存入的题目ID列表 random_trivia_id_list = request.session.get('random_trivia_ids') # 异常处理:session过期则跳转回答题页提示重试 if not random_trivia_id_list: return render(request, "ColdBlooded/trivia.html", {"error": "答题超时,请重新开始"}) trivia = Trivia.objects.filter(id__in=random_trivia_id_list) correct = 0 incorrect = 0 total = 0 for t in trivia: user_answer = request.POST.get(t.question) if t.answer == user_answer: correct += 1 else: incorrect += 1 total += 1 result = correct / total # 提交完成后清空session中的题目ID,避免用户下次答题复用同一套题 del request.session['random_trivia_ids'] return render(request, 'ColdBlooded/result.html', { "Incorrect": incorrect, "Correct": correct, "Total": total, "Trivia": trivia, "Result": result, }) else: # GET请求生成随机题目ID,存入session trivia_id_list = Trivia.objects.values_list('id', flat=True) random_trivia_id_list = random.sample(list(trivia_id_list), min(len(trivia_id_list), 3)) request.session['random_trivia_ids'] = random_trivia_id_list trivia = Trivia.objects.filter(id__in=random_trivia_id_list) return render(request, "ColdBlooded/trivia.html", { "Trivia": trivia })
Django默认已开启session功能,无需额外配置即可直接使用。
方案二:表单隐藏域传递抽题ID
无需依赖session,在GET渲染的答题页表单中新增隐藏输入框,将抽中的题目ID随用户答案一起提交,POST请求根据提交的ID查询对应题目即可。该方案支持用户多标签页同时答题互不干扰。
首先修改trivia.html的表单代码:
<form method="post"> {% csrf_token %} <!-- 新增隐藏域存储所有抽中的题目ID --> {% for t in Trivia %} <input type="hidden" name="trivia_ids" value="{{ t.id }}"> <!-- 原有题目、选项渲染代码保持不变 --> <p>{{ t.question }}</p> <input type="radio" name="{{ t.question }}" value="{{ t.option1 }}"> {{ t.option1 }}<br> <input type="radio" name="{{ t.question }}" value="{{ t.option2 }}"> {{ t.option2 }}<br> {% endfor %} <button type="submit">提交答案</button> </form>
再修改视图代码的POST逻辑:
def trivia(request): if request.method == 'POST': # 从POST参数读取提交的所有题目ID random_trivia_id_list = request.POST.getlist('trivia_ids') trivia = Trivia.objects.filter(id__in=random_trivia_id_list) # 后续判分逻辑和原有代码完全一致 correct = 0 incorrect = 0 total = 0 for t in trivia: user_answer = request.POST.get(t.question) if t.answer == user_answer: correct += 1 else: incorrect += 1 total += 1 result = correct / total return render(request, 'ColdBlooded/result.html', { "Incorrect": incorrect, "Correct": correct, "Total": total, "Trivia": trivia, "Result": result, }) else: # GET逻辑和原有代码保持一致 trivia_id_list = Trivia.objects.values_list('id', flat=True) random_trivia_id_list = random.sample(list(trivia_id_list), min(len(trivia_id_list),3)) trivia = Trivia.objects.filter(id__in=random_trivia_id_list) return render(request, "ColdBlooded/trivia.html", { "Trivia": trivia })
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

