Django 4:如何在视图外获取请求数据处理Quiz逻辑并返回上下文
解决Django Quiz系统中业务逻辑无法获取用户数据的问题
核心原则:业务逻辑不直接依赖请求上下文
quiz.py作为业务逻辑模块,不需要也不应该直接读取request或会话数据。正确的做法是在视图层(views.py)中提取所需的用户数据,再传递给quiz.py的函数,这既符合MVC分层设计,也能避免依赖混乱。
步骤1:重构quiz.py,让函数接收参数
把业务逻辑需要的用户数据(比如用户ID、过往答题记录、上一题结果)作为函数参数传入,而非让quiz.py主动去获取数据:
# quiz.py from .models import UserAnswer, Question def select_next_question(user_id, last_answer_result, last_question_id): # 从数据库读取用户过往答题记录 user_answers = UserAnswer.objects.filter(user_id=user_id).order_by('-created_at') # 执行你的选题算法(比如根据正确率调整难度、避免重复题目) # 示例逻辑:如果上题正确,选难度更高的题目;错误则选同难度或更低的 last_question = Question.objects.get(id=last_question_id) if last_answer_result: next_question = Question.objects.filter(difficulty__gte=last_question.difficulty).exclude(id=last_question_id).first() else: next_question = Question.objects.filter(difficulty__lte=last_question.difficulty).exclude(id=last_question_id).first() # 兜底:如果没有符合条件的题目,返回任意未答过的题目 if not next_question: answered_question_ids = [ans.question_id for ans in user_answers] next_question = Question.objects.exclude(id__in=answered_question_ids).first() return next_question
步骤2:在views.py中处理请求,传递数据到quiz.py
在处理提交答案或请求下一题的视图函数里,先从request中提取用户信息、提交的答题数据,再调用quiz.py的函数:
# views.py from django.shortcuts import render, redirect from .models import UserAnswer, Question from .quiz import select_next_question def submit_answer(request): if request.method == 'POST': # 获取用户提交的答题数据 question_id = request.POST.get('question_id') is_correct = request.POST.get('is_correct') == 'True' time_spent = int(request.POST.get('time_spent')) # 保存答题结果到数据库 UserAnswer.objects.create( user=request.user, question_id=question_id, is_correct=is_correct, time_spent=time_spent ) # 调用quiz.py的选题函数,传递必要参数 next_question = select_next_question( user_id=request.user.id, last_answer_result=is_correct, last_question_id=question_id ) # 渲染下一题页面 return render(request, 'quiz/question.html', {'question': next_question}) return redirect('quiz_start') def start_quiz(request): # 处理答题流程的第一题 answered_ids = [ans.question_id for ans in UserAnswer.objects.filter(user=request.user)] first_question = Question.objects.exclude(id__in=answered_ids).first() return render(request, 'quiz/question.html', {'question': first_question})
步骤3:移除不必要的复杂方案
你之前尝试的Middleware、Threading、Celery都不是当前场景的正确选择:
- Middleware用于全局请求/响应处理,不适合给业务逻辑传递数据
- Threading会引入并发风险,且你的选题逻辑需要实时响应,同步执行即可
- Celery用于异步后台任务(比如批量统计、发送通知),但选题是用户交互的实时逻辑,不需要异步处理
补充:支持匿名用户答题(可选)
如果允许匿名用户参与,可以用request.session存储答题记录,再传递给quiz.py:
# views.py 中处理匿名用户逻辑 def submit_answer(request): if not request.user.is_authenticated: # 从session获取匿名用户的答题记录 anonymous_answers = request.session.get('anonymous_answers', []) # 添加新答题记录到session anonymous_answers.append({ 'question_id': question_id, 'is_correct': is_correct, 'time_spent': time_spent }) request.session['anonymous_answers'] = anonymous_answers # 调用quiz.py的函数,传递session数据 next_question = select_next_question_for_anonymous( last_answer_result=is_correct, last_question_id=question_id, anonymous_answers=anonymous_answers ) return render(request, 'quiz/question.html', {'question': next_question}) # 登录用户逻辑同上...
内容的提问来源于stack exchange,提问作者user22145455
相关产品推荐
相关产品推荐

