为何共享layout.html的登录页无Flash消息,注册页却正常?
Flash消息仅在注册页显示,登录页不显示的原因及解决方法
问题描述
我尝试让Flash消息同时在登录页和注册页显示,两个页面均通过{% extends "layout.html" %}继承同一布局文件,但Flash消息在registration.html上显示正常,在login.html中完全不显示。
登录路由代码
@app.route("/login", methods=["GET", "POST"]) def login(): """Log user in""" # Forget any user_id session.clear() # User submitted form if request.method == "POST": # Ensure username was submitted if not request.form.get("username"): flash('Must provide username', 'error') return redirect("/login") # Ensure password was submitted elif not request.form.get("password"): flash('Must provide password', 'error') return redirect("/login") # Query database for username rows = db.execute("SELECT * FROM users WHERE username = ?", request.form.get("username")) # Ensure username exists and password is correct if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")): flash('Invalid username and/or password', 'error') return redirect("/login") # Remember which user has logged in session["user_id"] = rows[0]["id"] # Redirect user to home page return redirect("/") return render_template("login.html", messages=get_flashed_messages())
注册路由代码
@app.route("/register", methods=["GET", "POST"]) def register(): """Register user""" if request.method == "POST": if not request.form.get("username"): flash('Invalid Username.', 'error') return redirect("/register") elif not request.form.get("password"): flash('Invalid Password.', 'error') return redirect("/register") if request.form.get("password") != request.form.get("confirmation"): flash('Passwords do not match', 'error') return redirect("/register") rows = db.execute("SELECT * FROM users WHERE username = ?", request.form.get("username")) if len(rows) == 1: flash('Username already exists', 'error') return redirect("/register") username = request.form.get("username") hash = generate_password_hash(request.form.get("password"), method='pbkdf2:sha256', salt_length=8) db.execute("INSERT INTO users (username,hash) VALUES(?,?)", username, hash) return redirect("/login") return render_template("register.html", messages=get_flashed_messages())
布局文件layout.html代码
{% block content %} <div class="text-center"> {% for message in get_flashed_messages() %} <div class="alert alert-dark text-center" role="alert"> {{ message }} </div> {% endfor %} {% block page_content %}{% endblock %} </div> {% endblock %}
问题原因
核心问题出在登录路由的session.clear()调用位置:
- 登录函数开头的
session.clear()会在每次访问/login页面时执行(包括POST验证失败后重定向的GET请求),而Flash消息存储在session中,这会直接清空刚刚存入的Flash消息,导致后续get_flashed_messages()无法获取内容。 - 注册路由中没有全局的
session.clear()调用,Flash消息能保留到重定向后的GET请求中,因此可以正常显示。
另外,两个路由中render_template传入的messages参数是多余的,因为布局文件直接调用get_flashed_messages()而非使用该变量,但这不是登录页消息不显示的直接原因。
解决方法
将session.clear()移到POST请求的处理逻辑内部,仅在用户提交登录表单时清空session,避免影响重定向后的Flash消息:
修改后的登录路由代码:
@app.route("/login", methods=["GET", "POST"]) def login(): """Log user in""" # User submitted form if request.method == "POST": # 仅在处理登录请求时清空session session.clear() # Ensure username was submitted if not request.form.get("username"): flash('Must provide username', 'error') return redirect("/login") # Ensure password was submitted elif not request.form.get("password"): flash('Must provide password', 'error') return redirect("/login") # Query database for username rows = db.execute("SELECT * FROM users WHERE username = ?", request.form.get("username")) # Ensure username exists and password is correct if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")): flash('Invalid username and/or password', 'error') return redirect("/login") # Remember which user has logged in session["user_id"] = rows[0]["id"] # Redirect user to home page return redirect("/") return render_template("login.html")
同时可以移除render_template中多余的messages参数,因为布局文件并未使用该变量。
内容的提问来源于stack exchange,提问作者lozlf
相关产品推荐
相关产品推荐

