SQLAlchemy/Flask搜索结果传入Jinja模板时遇JSON序列化错误
解决Flask/SQLAlchemy中Media对象无法存入Session的序列化问题
问题根源
Flask的默认session机制会将存储的数据序列化为JSON格式(因为session数据保存在客户端Cookie中,必须可序列化)。你调用.all()确实得到了Media对象的列表,但每个Media都是SQLAlchemy的模型实例,不属于原生可JSON序列化的类型(如字典、基础数据类型)。当你把searchQuery存入session["results"]时,Flask自动尝试序列化这些对象,就会抛出TypeError: Object of type Media is not JSON serializable。
解决方法
方案1:将Media对象转换为字典列表
在存入session前,手动把每个Media实例转成字典,这样就能被正常序列化:
if(request.method=="POST" and len(request.form["searchBar"]) > 0): searchVal = request.form["searchBar"] startSearch = "%{}" genSearch = "%{}%" query1 = Media.query.filter_by(title=searchVal) query2 = Media.query.filter(Media.title.like(startSearch.format(searchVal))) query3 = Media.query.filter(Media.title.like(genSearch.format(searchVal))) searchQuery = query1.union(query2, query3).all() # 转换为可序列化的字典列表 session["results"] = [ { "mediaid": item.mediaid, "title": item.title, "year": item.year, "status": item.status, "mediatype": item.mediatype, "seriesid": item.seriesid, "externalinfo": item.externalinfo, "extranotes": item.extranotes } for item in searchQuery ] return redirect(url_for("results"))
之后在Jinja模板中直接遍历字典即可访问对应字段。
方案2:改用服务器端Session
使用Flask-Session扩展将session存储在服务器端(如文件、Redis或数据库),这样不需要将对象序列化为JSON。
- 安装扩展:
pip install flask-session - 配置并初始化:
from flask import Flask from flask_session import Session app = Flask(__name__) # 配置session存储类型为文件系统 app.config["SESSION_TYPE"] = "filesystem" app.config["SECRET_KEY"] = "your-secret-key-here" # 必须设置秘钥 Session(app)
配置完成后,你可以直接将Media对象列表存入session,无需额外转换。
方案3:重定向时传递ID,在结果页重新查询
不通过session传递数据,而是将查询到的mediaid拼接成字符串作为查询参数传给结果页,再重新查询数据:
# 提交搜索的视图 if(request.method=="POST" and len(request.form["searchBar"]) > 0): searchVal = request.form["searchBar"] startSearch = "%{}" genSearch = "%{}%" query1 = Media.query.filter_by(title=searchVal) query2 = Media.query.filter(Media.title.like(startSearch.format(searchVal))) query3 = Media.query.filter(Media.title.like(genSearch.format(searchVal))) searchQuery = query1.union(query2, query3).all() # 拼接mediaid为字符串 media_ids = ",".join(str(item.mediaid) for item in searchQuery) return redirect(url_for("results", media_ids=media_ids))
# 结果页视图 @app.route("/results") def results(): media_ids = request.args.get("media_ids", "") search_results = [] if media_ids: ids_list = list(map(int, media_ids.split(","))) # 根据ID重新查询数据 search_results = Media.query.filter(Media.mediaid.in_(ids_list)).all() return render_template("results.html", results=search_results)
这种方式更符合HTTP无状态特性,也避免了session序列化问题。
内容的提问来源于stack exchange,提问作者user3010445
相关产品推荐
相关产品推荐

