SQLAlchemy检索排名最高的评分消息列表,多对多 - 用户消息

时间:2016-12-14 05:13:30

标签: python sqlalchemy flask-sqlalchemy

我正在尝试检索最高得分线程启动消息的排序列表。分数的计数应该只是喜欢 - 不喜欢消息。

目前无法正常工作,尽管消息有多少喜欢和不喜欢,但得分总是为0。错误可能在下面的“运行代码”部分,因为其余部分似乎有效,但我不完全确定。

用户只能喜欢或不喜欢消息,所以我为用户和消息之间的喜欢和不喜欢做了两个单独的关系。因此,我可以很容易地跟踪用户所做的操作,并且我能够向用户显示它在UI中采取的操作。

感觉不够深入,我不知道我的方法是否是最好的方法,希望你可以帮助我走上正确的道路并帮助那些制造喜欢/不喜欢系统的人。感谢我得到的所有帮助!

表格:

like_table = db.Table('like', db.metadata,
    db.Column('user', db.Integer, db.ForeignKey('user.id')),
    db.Column('message', db.Integer, db.ForeignKey('message.id')))

dislike_table = db.Table('dislike', db.metadata,
    db.Column('user', db.Integer, db.ForeignKey('user.id')),
    db.Column('message', db.Integer, db.ForeignKey('message.id')))

用户类:

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True)
    password = db.Column(db.String(255))
    reg_date = db.Column(db.DateTime)

    likes = db.relationship('Message', secondary=like_table, back_populates = 'likers')
    dislikes = db.relationship('Message', secondary=dislike_table, back_populates = 'dislikers')

    def __init__(self, uname, password):
        self.username = uname
        self.password = generate_password_hash(password)
        self.reg_date = datetime.utcnow()

Message类:

class Message(db.Model):
    __tablename__ = 'message'
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String(500))
    post_date = db.Column(db.DateTime)
    writer = db.Column(db.String(128))
    writer_id = db.Column(db.Integer)
    thread_start = db.Column(db.Boolean) # if it's the start of a thread

    likers = db.relationship('User', secondary=like_table, back_populates = 'likes')
    dislikers = db.relationship('User', secondary=dislike_table, back_populates = 'dislikes')

    def __init__(self, text, writer, thread_start):
        self.text = text
        self.post_date = datetime.utcnow()
        self.writer = writer.username
        self.writer_id = writer.id
        self.thread_start = thread_start

    @hybrid_property
    def score(self):
       return func.count(Message.likers) - func.count(Message.dislikers)

要运行的代码(这里可能有问题):

top_voted_threads = db.session.query(Message, Message.score.label('total')).\
    filter(Message.thread_start == True).\
    join(Message.likers, aliased = True).join(Message.dislikers).\
    group_by(Message).order_by('total DESC')[0:10]
print(top_voted_threads)

当前输出,分数错误地为0:

[(<app.Message object at 0x103f42278>, 0), (<app.Message object at 0x103f42e48>, 0), (<app.Message object at 0x103f688d0>, 0), (<app.Message object at 0x103f68588>, 0)]

1 个答案:

答案 0 :(得分:0)

您没有正确使用@hybrid_attribute。将您的score拆分为like_scoredislike_score以查看疯狂的数字,因为您拥有的func.count(...)基本上会生成不相关的查询。

下面应该会了解如何使用混合物来实现您的目的:

class Message(Base):
    ...

    @hybrid_property
    def num_likers(self):
        return len(self.likers)

    @num_likers.expression
    def _num_likes_expression(cls):
        return (
            select([func.count('*').label("num_likes_value")])
            .where(like_table.c.message == cls.id)
            .label("num_likers")
        )

    @hybrid_property
    def num_dislikers(self):
        return len(self.dislikers)

    @num_dislikers.expression
    def _num_dislikes_expression(cls):
        return (
            select([func.count('*').label("num_dislikes_value")])
            .where(dislike_table.c.message == cls.id)
            .label("num_dislikers")
        )

    @hybrid_property
    def score(self):
        return self.num_likers - self.num_dislikers