【问题标题】:SQLAlchemy table defining relationship using two foreign keysSQLAlchemy 表使用两个外键定义关系
【发布时间】:2020-12-23 16:12:03
【问题描述】:

我有两个表,Users 和 ChatSessions。 ChatSessions 有两个字段,user_id 和friend_id,它们都是Users 表的外键。

user_id 始终包含发起聊天会话的用户,friend_id 是其他用户。由于某个用户可以有他自己或他的朋友发起的聊天会话,因此他可以在各种会话中将他的 id 作为 user_id 或friend_id。

是否可以在用户表中定义关系,我可以访问该用户的所有聊天会话,无论他的 id 是在 user_id 还是friend_id 中? 像这样的:

chat_sessions = db.relationship('chat_sessions',
                primaryjoin="or_(User.id==ChatSession.user_id, User.id==ChatSession.friend_id)",
                backref="user")

当我尝试向用户表提交条目时收到以下错误:

ERROR   main.py:76      [10.0.2.2] Unhandled Exception [93e3f515-7dd6-4e8d-b096-8239313433f2]: relationship 'chat_sessions' expects a class or a mapper argument (received: <class 'sqlalchemy.sql.schema.Table'>)

模型:

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(60), index=True, unique=True)
    password = db.Column(db.String(255))
    name = db.Column(db.String(100))
    active = db.Column(db.Boolean(), nullable=False)

    chat_sessions = db.relationship('chat_sessions',
                    primaryjoin="or_(User.id==ChatSession.user_id, User.id==ChatSession.friend_id)")



class ChatSession(db.Model):
    __tablename__ = 'chat_sessions'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    friend_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    status = db.Column(db.String(50))


    user = db.relationship('User', foreign_keys=[user_id])
    friend = db.relationship('User', foreign_keys=[friend_id])

【问题讨论】:

    标签: python sql sqlalchemy flask-sqlalchemy


    【解决方案1】:

    如果没有看到表的代码很难确定,但删除 backref 参数可能就足够了。

    这是一个纯粹的 SQLAlchemy 实现,似乎可以满足您的需求:

    import sqlalchemy as sa
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import orm
    
    
    Base = declarative_base()
    
    
    class User(Base):
        __tablename__ = 'users'
        id = sa.Column(sa.Integer, primary_key=True)
        name = sa.Column(sa.String)
    
        all_chats = orm.relationship('Chat',
            primaryjoin="or_(User.id==Chat.user_id, User.id==Chat.friend_id)")
    
        def __repr__(self):
            return f'User(name={self.name})'
    
    
    class Chat(Base):
        __tablename__ = 'chats'
    
        id = sa.Column(sa.Integer, primary_key=True)
        user_id = sa.Column(sa.Integer, sa.ForeignKey('users.id'))
        friend_id = sa.Column(sa.Integer, sa.ForeignKey('users.id'))
    
        user = orm.relationship('User', foreign_keys=[user_id])
        friend = orm.relationship('User', foreign_keys=[friend_id])
    
        def __repr__(self):
            return f'Chat(user={self.user.name}, friend={self.friend.name})'
    
    
    engine = sa.create_engine('sqlite:///')
    Base.metadata.create_all(bind=engine)
    Session = orm.sessionmaker(bind=engine)
    
    usernames = ['Alice', 'Bob', 'Carol']
    session = Session()
    users = [User(name=name) for name in usernames]
    session.add_all(users)
    session.flush()
    
    a, b, c = users
    
    session.add(Chat(user_id=a.id, friend_id=b.id))
    session.add(Chat(user_id=a.id, friend_id=c.id))
    session.add(Chat(user_id=c.id, friend_id=a.id))
    session.commit()
    session.close()
    
    session = Session()
    users = session.query(User)
    for user in users:
        for chat in user.all_chats:
            print(user, chat)
        print()
    session.close()
    

    这是输出:

    User(name=Alice) Chat(user=Alice, friend=Bob)
    User(name=Alice) Chat(user=Alice, friend=Carol)
    User(name=Alice) Chat(user=Carol, friend=Alice)
    
    User(name=Bob) Chat(user=Alice, friend=Bob)
    
    User(name=Carol) Chat(user=Alice, friend=Carol)
    User(name=Carol) Chat(user=Carol, friend=Alice)
    

    【讨论】:

    • 感谢您的回复。不幸的是,我仍然有这个错误: ERROR in main: [10.0.2.2] Unhandled Exception [c5815dd8-79dd-4e63-954b-f6f0de83e481]: relationship 'chat_sessions' expects a class or a mapper argument (received: ) 被抛出,否则有效,查询:user = User.query.filter_by(email=user_email).first()
    • 请编辑您的问题以显示您的模型。如果没有看到您的代码,就无法确定如何修复您的错误。
    • 编辑了原始问题。
    • 看起来你应该有db.relationship('ChatSession', ...):relationship 的第一个参数应该是模型类的名称,而不是表的名称。
    • 没错。感谢您及时和详尽的帮助。
    猜你喜欢
    • 2021-07-10
    • 1970-01-01
    • 2017-05-24
    • 2013-09-19
    • 2012-02-29
    • 2016-10-06
    • 1970-01-01
    • 2014-11-09
    • 2015-02-15
    相关资源
    最近更新 更多