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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 00:10:21