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>
问题根源
- Session可变对象修改未触发持久化:Flask Session对列表这类可变对象的修改,默认不会自动检测变化。执行
session['incorrect_types'].append()仅修改了列表内容,但Session未感知到变化,不会保存更新后的数据。 - 模式选择时的不必要重置:选择practice/random模式时,代码执行
session['incorrect_types'] = []清空了历史错误题型,导致练习模式无法获取有效数据。 - 遗漏第二题错误记录:原代码仅处理第一题的错误,第二题的错题题型完全未被记录。
修复方案与修改后代码
修改后的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)
关键修改点
- 手动触发Session更新:每次向
incorrect_types追加元素后,添加session.modified = True,确保Flask感知到Session变化并持久化。 - 移除错误题型重置:删除模式选择分支中的
session['incorrect_types'] = [],保留历史错误数据供练习模式使用。 - 补充第二题错误处理:新增第二题的答案判断和错误题型记录逻辑,确保所有错题都被追踪。
- 完善结果消息:根据答对数量生成精准提示,并展示错题的正确答案。
- 初始化practice_wrong:在Session初始化阶段添加
practice_wrong的默认值,避免KeyError。
内容的提问来源于stack exchange,提问作者user24204655
相关产品推荐
相关产品推荐

