简体   繁体   中英

Flask SQLAlchemy - How to order query result by count of ForeignKey variable

I'm implementing blog posts type Flask app using Flask-SQLAlchemy.

I'm trying to order the blog posts based on total number of likes each blog post received. I've tried using SQLALchemy hybrid property with query session.query(Post).order_by(Post.likes_count.desc()).all() which is similar to solution to a question asked earlier here

It throws error AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Post.likes has an attribute 'count'

Is there a way to get posts order using likes count which needs to be fed to paginate function.

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20))
    email = db.Column(db.String(120))
    likes = db.relationship('Like', backref='user',lazy='dynamic',foreign_keys='Like.user_id')
    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    date_posted = db.Column(db.DateTime, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    likes = db.relationship('Like', backref='post', lazy='dynamic')

    @hybrid_property
    def likes_count(self):
        return self.likes.count()

    def __repr__(self):
        return f"Post('{self.title}', '{self.date_posted}')"

class Like(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))

This question is similar to How to order by count of many-to-many relationship in SQLAlchemy? However I was not able to get query results with len or count() method mentioned in answer/comments.

The way I would do it is by using sqlalchemy's func functionality , which just mirrors a SQL function. In this case, that would most likely be the following:

from sqlalchemy import func

session.query(Post).join(Like).group_by(Post.id).order_by(func.count().desc()).all()

This query results in something like the following raw SQL (although I just tried to make it a little cleaner by not writing everything out):

SELECT post.*
FROM post
JOIN like ON like.post_id = post.id
GROUP BY post.id
ORDER BY count() desc

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM