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

Flask Session变量无法保留值问题求助

Flask Session变量异常问题:incorrect_types数组在GET请求时为空

问题背景

开发的Flask答题程序核心功能:

  • 从数据库获取随机题目
  • 每完成3道题后,用户可选择「practice(练习模式)」或「random(随机模式)」
  • 练习模式仅推送用户过往答错的题型(对应session中的incorrect_types数组)

当前异常:incorrect_types数组在用户答错题目时已正确追加题型,但GET请求时的DEBUG语句显示该数组为空。

原代码

Flask代码

from flask import Flask, g, session, request, redirect, url_for, render_template
import sqlite3

app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
DATABASE = "qa_database.db"

def get_db():
    db = getattr(g, "_database", None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, "_database", None)
    if db is not None:
        db.close()

@app.route("/", methods=["GET", "POST"])
def home():
    db = get_db()
    cursor = db.cursor()
    # Initialize session variables if they don't exist
    if 'counter' not in session:
        session['counter'] = 0
    if 'incorrect_types' not in session:
        session['incorrect_types'] = []

    if request.method == "POST":
        # Check if the user has made a choice on question types
        if 'choice' in request.form:
            if request.form['choice'] == 'practice':
                session['practice_wrong'] = True
            else:
                session['practice_wrong'] = False
            
            session['counter'] = 0  # Reset the counter after making a choice
            session['incorrect_types'] = []  # Reset the incorrect types
            
            # Debug statement
            print("practice_wrong set to:", session['practice_wrong'])
            
            return redirect(url_for('home'))
        # Get user answers from the form
        answer1 = request.form.get("answer1")
        answer2 = request.form.get("answer2")

        # Retrieve questions, correct answers, and types from session
        question1 = session.get("question1")
        correct_answer1 = session.get("correct_answer1")
        question1_type = session.get("question1_type")
        # Initialize message
        message = ""
        # Initialize a flag to indicate if the choice buttons should be shown
        show_choice = False
        if question1 and correct_answer1:
            # Check if answers are correct and log incorrect types
            if answer1.lower() == correct_answer1.lower():
                message = "Well Done! You got both correct."
            elif answer1.lower() != correct_answer1.lower():
                session['incorrect_types'].append(question1_type)
                message = "Oops! You got both wrong."
                message += f"<br><br>Correct Answer: {correct_answer1}<br>Your Answer: {answer1}"        
        # Increment the counter
        session['counter'] += 1

        # Check if it's time to offer the user a choice
        if session['counter'] % 3 == 0:
            show_choice = True
            # Get the unique topics the user got wrong
            unique_incorrect_types = list(set(session['incorrect_types']))
            # Create a message based on the number of topics
            if unique_incorrect_types:
                topics_list = ", ".join(unique_incorrect_types)
                message = f"You've been getting questions wrong in topics: {topics_list}. Want to practice on these topics?"
                print(unique_incorrect_types)  
            else:
                message = "Want to practice on the topics you're failing?"

        # Render the home page with the message and choice buttons if needed
        return render_template("home.html", message=message, submitted=True, next_question=not show_choice, show_choice=show_choice)
    else:
        print("DEBUG STATEMENT", session['incorrect_types']) #ARRAY IS EMPTY 
        if session.get('practice_wrong', False) and session['incorrect_types']:
            # Convert the list of incorrect types to a set to remove duplicates, then back to a list
            types_list = list(set(session['incorrect_types']))
            # Create a string of placeholders that match the length of types_list
            placeholders = ','.join('?' * len(types_list))
            # Execute the query with the list of types
            cursor.execute(f"SELECT question, correct_answer, type FROM Questions WHERE type IN ({placeholders}) ORDER BY RANDOM()", types_list)
        else:
            cursor.execute("SELECT question, correct_answer, type FROM Questions ORDER BY RANDOM()")
        
        questions = cursor.fetchall()

        if len(questions) >= 2:
            # Store questions, correct answers, and types in session
            question1, correct_answer1, question1_type = questions[0]
            question2, correct_answer2, question2_type = questions[1]
            session["question1"] = question1
            session["correct_answer1"] = correct_answer1
            session["question1_type"] = question1_type
            # Render the home page with the random questions
            return render_template("home.html", question1=question1, question2=question2, submitted=False, next_question=False)
        else:
            return "There are not enough questions in the database."

if __name__ == "__main__":
    app.run(debug=True)

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Question and Answer</title>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='homeCSS.css') }}">
</head>
<body>
    <h1>Answer the Questions</h1>
    {% if not submitted %}
    <form method="POST">
        <p>{{ question1 }}</p>
        <input type="text" name="answer1" required>
        <br>
        <p>{{ question2 }}</p>
        <input type="text" name="answer2" required>
        <br>
        <br>
        <input type="submit" value="Submit">
    </form>
    {% endif %}
    {% if message %}
        <p>{{ message|safe }}</p>
    {% endif %}
    {% if next_question %}
        <a href="/">Next Question</a>
    {% endif %}
    {% if show_choice %}
    <p>{{ message|safe }}</p>
    <form method="POST">
        <input type="submit" name="choice" value="practice">
        <input type="submit" name="choice" value="random">
    </form>
{% endif %}
</body>
</html>

问题根源

  1. Session可变对象修改未触发持久化:Flask Session对列表这类可变对象的修改,默认不会自动检测变化。执行session['incorrect_types'].append()仅修改了列表内容,但Session未感知到变化,不会保存更新后的数据。
  2. 模式选择时的不必要重置:选择practice/random模式时,代码执行session['incorrect_types'] = []清空了历史错误题型,导致练习模式无法获取有效数据。
  3. 遗漏第二题错误记录:原代码仅处理第一题的错误,第二题的错题题型完全未被记录。

修复方案与修改后代码

修改后的Flask代码

from flask import Flask, g, session, request, redirect, url_for, render_template
import sqlite3

app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
DATABASE = "qa_database.db"

def get_db():
    db = getattr(g, "_database", None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, "_database", None)
    if db is not None:
        db.close()

@app.route("/", methods=["GET", "POST"])
def home():
    db = get_db()
    cursor = db.cursor()
    # Initialize session variables if they don't exist
    if 'counter' not in session:
        session['counter'] = 0
    if 'incorrect_types' not in session:
        session['incorrect_types'] = []
    if 'practice_wrong' not in session:
        session['practice_wrong'] = False

    if request.method == "POST":
        # Check if the user has made a choice on question types
        if 'choice' in request.form:
            session['practice_wrong'] = request.form['choice'] == 'practice'
            session['counter'] = 0  # Reset the counter after making a choice
            print("practice_wrong set to:", session['practice_wrong'])
            return redirect(url_for('home'))
        
        # Get user answers from the form
        answer1 = request.form.get("answer1")
        answer2 = request.form.get("answer2")

        # Retrieve questions, correct answers, and types from session
        question1 = session.get("question1")
        correct_answer1 = session.get("correct_answer1")
        question1_type = session.get("question1_type")
        question2 = session.get("question2")
        correct_answer2 = session.get("correct_answer2")
        question2_type = session.get("question2_type")
        
        # Initialize message
        message = ""
        # Initialize a flag to indicate if the choice buttons should be shown
        show_choice = False
        correct_count = 0
        
        # 处理第一题答案
        if question1 and correct_answer1:
            if answer1.lower() == correct_answer1.lower():
                correct_count +=1
            else:
                session['incorrect_types'].append(question1_type)
                session.modified = True  # 手动标记Session已修改
        
        # 处理第二题答案
        if question2 and correct_answer2:
            if answer2.lower() == correct_answer2.lower():
                correct_count +=1
            else:
                session['incorrect_types'].append(question2_type)
                session.modified = True  # 手动标记Session已修改
        
        # 设置结果消息
        if correct_count ==2:
            message = "Well Done! You got both correct."
        elif correct_count ==0:
            message = "Oops! You got both wrong."
            message += f"<br><br>Correct Answer 1: {correct_answer1}<br>Your Answer 1: {answer1}"
            message += f"<br><br>Correct Answer 2: {correct_answer2}<br>Your Answer 2: {answer2}"
        else:
            message = f"You got {correct_count} out of 2 correct."
            if not answer1.lower() == correct_answer1.lower():
                message += f"<br><br>Correct Answer 1: {correct_answer1}<br>Your Answer 1: {answer1}"
            if not answer2.lower() == correct_answer2.lower():
                message += f"<br><br>Correct Answer 2: {correct_answer2}<br>Your Answer 2: {answer2}"
        
        # Increment the counter
        session['counter'] += 1

        # Check if it's time to offer the user a choice
        if session['counter'] % 3 == 0:
            show_choice = True
            # Get the unique topics the user got wrong
            unique_incorrect_types = list(set(session['incorrect_types']))
            # Create a message based on the number of topics
            if unique_incorrect_types:
                topics_list = ", ".join(unique_incorrect_types)
                message = f"You've been getting questions wrong in topics: {topics_list}. Want to practice on these topics?"
                print(unique_incorrect_types)  
            else:
                message = "Want to practice on the topics you're failing?"

        # Render the home page with the message and choice buttons if needed
        return render_template("home.html", message=message, submitted=True, next_question=not show_choice, show_choice=show_choice)
    else:
        print("DEBUG STATEMENT", session['incorrect_types'])
        if session.get('practice_wrong', False) and session['incorrect_types']:
            # Convert the list of incorrect types to a set to remove duplicates, then back to a list
            types_list = list(set(session['incorrect_types']))
            # Create a string of placeholders that match the length of types_list
            placeholders = ','.join('?' * len(types_list))
            # Execute the query with the list of types
            cursor.execute(f"SELECT question, correct_answer, type FROM Questions WHERE type IN ({placeholders}) ORDER BY RANDOM()", types_list)
        else:
            cursor.execute("SELECT question, correct_answer, type FROM Questions ORDER BY RANDOM()")
        
        questions = cursor.fetchall()

        if len(questions) >= 2:
            # Store questions, correct answers, and types in session
            question1, correct_answer1, question1_type = questions[0]
            question2, correct_answer2, question2_type = questions[1]
            session["question1"] = question1
            session["correct_answer1"] = correct_answer1
            session["question1_type"] = question1_type
            session["question2"] = question2
            session["correct_answer2"] = correct_answer2
            session["question2_type"] = question2_type
            # Render the home page with the random questions
            return render_template("home.html", question1=question1, question2=question2, submitted=False, next_question=False)
        else:
            return "There are not enough questions in the database."

if __name__ == "__main__":
    app.run(debug=True)

关键修改点

  1. 手动触发Session更新:每次向incorrect_types追加元素后,添加session.modified = True,确保Flask感知到Session变化并持久化。
  2. 移除错误题型重置:删除模式选择分支中的session['incorrect_types'] = [],保留历史错误数据供练习模式使用。
  3. 补充第二题错误处理:新增第二题的答案判断和错误题型记录逻辑,确保所有错题都被追踪。
  4. 完善结果消息:根据答对数量生成精准提示,并展示错题的正确答案。
  5. 初始化practice_wrong:在Session初始化阶段添加practice_wrong的默认值,避免KeyError。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:44:54