如何搜索Flask SQLAlchemy多对多关系的表?

3 投票
1 回答
7182 浏览
提问于 2025-04-17 13:43

我有以下的模型和表:

chat_members = db.Table('chat_members',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('chat_id', db.Integer, db.ForeignKey('chat.id'))
)

class chat(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    start_date = db.Column(db.DateTime)
    chat_memb = db.relationship('user', secondary=chat_members, backref=db.backref('members', lazy='dynamic'))  
    chat_line = db.relationship('line', backref='chat_line', lazy='dynamic')

    def __repr__(self):
        return '<Chat %r>' % (self.id)

class user(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_email = db.Column(db.String, unique=True)
    user_password = db.Column(db.String)
    lines = db.relationship('line', backref='line_author', lazy='dynamic')

    def __repr__(self):
        return '<User %r>' % (self.user_email)

class line(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    published_date = db.Column(db.DateTime)
    chat_id = db.Column(db.Integer, db.ForeignKey('chat.id'))
    sent_by = db.Column(db.Integer, db.ForeignKey('user.id'))
    line_text = db.Column(db.String)


    def __repr__(self):
        return '<Line %r>' % (self.id)

我已经成功地向这些模型中添加了数据,但在查询表的时候遇到了问题。我的最终目标是查找与特定用户相关的所有聊天记录。以下是我所做的:

first_user = user.query.get(1)
chat.query.filter(chat_members.any(chat_memb=first_user)).all()

结果我得到了:

sqlalchemy.exc.InvalidRequestError: 不能将集合与对象或集合进行比较;请使用 contains() 来测试成员资格。

这个问题(http://stackoverflow.com/questions/12593421/sqlalchemy-and-flask-how-to-query-many-to-many-relationship)看起来很相似,但当我把它复制到我的模型上时,得到了 AttributeError: type object 'chat' has no attribute 'members' 的错误,之后我做了:

chat.query.filter(chat.members.any(user_email='ACCEPTABLE_EMAIL')).all()

这个错误让我很意外,因为 memberschat 模型中的反向引用,但我觉得这个查询还是很接近我想要的结果。

我找到的其他相关问题似乎没有提供关于相同查询的建议,而且在官方文档或第三方的多对多文档中也找不到这样的查询。

1 个回答

13

你需要在你的查询中使用连接(joins)。首先,把你的 chat.chat_memb 关系改成:

# Change backref from 'members' to 'chats', since the backref will be pointing
# to chat class.
chat_memb = db.relationship('user', secondary=chat_members,
                            backref=db.backref('chats', lazy='dynamic'))

然后使用这个查询:

chat.query.join(user.chats).filter(user.id == 1).all()

我还建议你遵循Python的命名规范,给类起个大写的名字,比如用 Chat 而不是 chat。这样在你的代码中就不容易把类和实例搞混了。

撰写回答