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

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。

  1. 安装扩展:pip install flask-session
  2. 配置并初始化:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:57:36