首页 > 解决方案 > 如何在 Flask-SQLAlchemy 中按用户获取不同列条目的数量?

问题描述

我有一个用户活动数据库。对于特定用户,我想返回他们所做的不同类型活动的数量。例如:

Bob:
活动 1:A 型
活动 2:B 型
活动 3:A 型

结果应该是 2,因为有两个不同的活动(A 和 B)。

我尝试了以下命令:

Activity.activity_type.query.filter(Activity.user_id==1).distinct(Activity.activity_type) 

Activity.activity_type部分给出错误。我查看了 StackOverflow 和文档,但找不到distinct在这种情况下如何正确使用。我将不胜感激有关如何使此查询正常工作的帮助。

标签: pythonsqlalchemyflask-sqlalchemy

解决方案


请原谅我对您的目标的原始解释,它不正确,因为返回了每个尝试的活动的计数,而不是尝试的不同活动的计数。

有关 Ilja Everilä 在评论中提供的问题的解决方案,请参见下文。

但是,您遇到的异常发生在您的查询执行之前(我认为,因为我已经从您提供的查询中对您的模型进行了逆向工程)所以这个答案的大部分集中在:

AttributeError:与 Activity.activity_type 关联的“InstrumentedAttribute”对象和“比较器”对象都没有属性“查询”

我创建了这些模型以执行您的查询:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(16))

class Activity(db.Model):
    activity_id = db.Column(db.Integer, primary_key=True)
    activity_type = db.Column(db.String(32))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    user = db.relationship('User')

然后写了一个小脚本来添加一些数据:

if __name__ == '__main__':
    with app.app_context():
        db.drop_all()
        db.create_all()
        names = ['batman', 'a', 'list', 'of', 'names']
        users = [User(name=name) for name in names]
        db.session.add_all(users)
        activities = [
            'Self Doubt',
            'Dark Introspection',
            'Gotham Needs Me',
            'Training Montage',
            'Fight Crime',
            'Get the girl'
        ]
        db.session.add_all(
            [Activity(
                activity_type=random.choice(activities),
                user=random.choice(users)
            ) for _ in range(20)]
        )

        db.session.commit()

执行Activity.activity_type.query.filter(Activity.user_id==1).distinct(Activity.activity_type)会引发上述错误。

问题来自您查询的这一部分Activity.activity_type.query。这就是说它正在寻找一个调用的属性'query'Activity.activity_type找不到它。将错误消息分解一下:

我们知道这是我们在模型上定义它时Activity.activity_type的一个实例,但是却显示了,所以这是错误中引用的第一个对象。这是一个内部 sqlalchemy 构造,它也被检查(如果你有兴趣,你可以找到它)。因此 sqlalchemy 查找并找不到列上具有名称的属性。Columnprint(Activity.activity_type)<class 'sqlalchemy.orm.attributes.InstrumentedAttribute'>ComparitorActivity.activity_type.comparator'query'Activity.activity_type

.query属性来自db.Model您的模型继承的基础,并且仅可用于db.Model. 由于列对象不继承自db.Model,因此您无法通过它们访问查询属性。Activity.query是合法的,Activity.activity_type.query不是。

这是 Ilja 在对我的原始答案的评论中提供的查询,这是正确的解决方案:

        batman_activity_count = db.session.query(
            db.func.count(
                Activity.activity_type.distinct()
            )
        ).filter(Activity.user_id==1).scalar()

        print(batman_activity_count)  # random integer b/w 0 and 6.

推荐阅读