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

Flask首页结合搜索与排序算法时出现属性错误的问题排查

Flask搜索结合Reddit热门排序多帖返回时的AttributeError问题

我在Flask中编写了如下index视图函数,实现简单搜索与Reddit热门排序算法的结合:

@views.route("/index")
@login_required
def index():
    search = request.args.get("search")

    if search:
        posts = Post.query.filter(Post.title.contains(
            search) | Post.text.contains(search))

    else:
        posts = Post.query.all()

    for post in posts:
        date = post.date_created
        ups = len(post.likes)
        downs = len(post.dislikes)
        post.hot_score = hot(ups, downs, date)

        #print(post)
        #print(post.hot_score)
        
    sorted_posts = sorted(posts, key=lambda post: post.hot_score, reverse=True)
    
    return render_template("index.html", user=current_user, posts=sorted_posts)

单独使用搜索或排序功能都正常,当搜索仅返回单篇帖子时二者协同工作也正常,但搜索返回多篇帖子时会触发错误:AttributeError: 'Post' object has no attribute 'hot_score'。我尝试注释sorted_posts相关代码,直接返回posts=posts,此时多帖子搜索能正常运行,且打印显示每个Post对象都带有hot_score属性。参考用的Post模型代码如下:

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(60), nullable=False)
    text = db.Column(db.Text, nullable=False)
    date_created = db.Column(db.DateTime(timezone=True), default=func.now())
    author_id = db.Column(db.Integer, db.ForeignKey(
        "user.id", ondelete="CASCADE"), nullable=False)
    comments = db.relationship("Comment", backref="post", passive_deletes=True)
    likes = db.relationship('Like', backref='post', passive_deletes=True)
    dislikes = db.relationship('Dislike', backref='post', passive_deletes=True)

问题原因

问题出在Flask-SQLAlchemy的惰性查询特性上:当搜索时,Post.query.filter(...)返回的是一个Query对象,而非直接的列表。第一次遍历posts时,ORM会执行查询并加载Post对象,此时给每个对象添加了hot_score属性。但sorted()函数会再次遍历这个Query对象,ORM会重新执行数据库查询,生成一批全新的Post对象——这些新对象并没有被添加过hot_score属性,因此触发了属性不存在的错误。而单帖返回时,Query对象可能只加载一次,后续遍历复用了同一个对象,所以没出现问题。

解决方案

把查询结果转换成列表,确保后续所有操作都针对同一批对象:

方法一:在搜索分支直接转成列表

修改视图函数中的搜索逻辑:

if search:
    # 把Query对象转为列表,避免后续重复查询生成新对象
    posts = list(Post.query.filter(Post.title.contains(search) | Post.text.contains(search)))
else:
    posts = Post.query.all()

方法二:遍历前统一转成列表

不管是搜索还是默认情况,都先把结果转为列表:

# 统一转换为列表
posts = list(posts)
for post in posts:
    date = post.date_created
    ups = len(post.likes)
    downs = len(post.dislikes)
    post.hot_score = hot(ups, downs, date)

这样后续排序操作的就是已经添加了hot_score属性的同一批对象,就不会再出现AttributeError了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:17:50