簡體   English   中英

自引用多對多關系與關聯 object 中的額外列

[英]Self referencing many-to-many relationship with extra column in association object

我是 Sqlalchemy 的新手,並試圖通過relationship()實現以下目標:

  1. 有一個存儲用戶數據的User表。
  2. 每個用戶都可以使用邀請碼邀請其他invite_code
  3. 每個用戶都有一個invitation列表,每個invitation都包含invite_code和被邀請User

我認為UserInvitation之間的關系是一對多的。 由於Invitation包含User ,那么我認為使用自引用關系來表示邀請者到邀請(被邀請者)關系並使用關聯invite_code來存儲邀請碼可能會更好。

我檢查了sqlalchemy 文檔問題,試圖實現這樣的分類:

from sqlalchemy import Column, Integer, ForeignKey, create_engine, String
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Invitation(Base):
    __tablename__ = 'invitation'

    invite_code = Column(Integer)
    inviter_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    invitee_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    
    invitee = relationship('User') #Need HELP here

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)

    inviters = relationship('User',
                            secondary='invitation',
                            primaryjoin=id==Invitation.invitee_id,
                            secondaryjoin=id==Invitation.inviter_id,
                            backref='invitees')

    invitations = relationship('Invitation')# Need HELP here

    def __repr__(self):
        return f'User: {self.name}'

if __name__ == '__main__':
    engine = create_engine('sqlite://')
    Base.metadata.create_all(engine)
    Session = sessionmaker(engine)

    db = Session()

    inviter1 = User(name='inviter1')
    inviter2 = User(name='inviter2')

    invitee1= User(name='invitee1')
    invitee2 = User(name='invitee2')

    inviter1.invitees = [invitee1, invitee2]
    inviter2.invitees = [invitee1]

    db.add(inviter1)
    db.add(inviter2)
    db.add(invitee1)
    db.add(invitee2)
    db.commit()

    users = db.query(User).all()
    for user in users:
        print(user)
        print(' Inviter: ', user.inviters)
        print(' Invitee: ', user.invitees)
        print()


如果#Need HELP here的行被刪除,我可以得到對應的invitationer和被邀請人,但不能得到invite_code 如果添加#Need HELP here代碼,則錯誤為:

Exception has occurred: AmbiguousForeignKeysError
Could not determine join condition between parent/child tables on relationship Invitation.invitee - there are multiple foreign key paths linking the tables.  Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

有沒有辦法在關聯 object 中添加額外的數據列,例如關聯 object 用於自引用表的多對多關系

抱歉文字太多,在web上沒有找到任何參考文檔。

最后,我在foreign_keys的幫助下弄清楚了:

from sqlalchemy import Column, Integer, ForeignKey, create_engine, String
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)

    sent_invitations = relationship('Invitation', foreign_keys='Invitation.inviter_id', back_populates='inviter', cascade='all, delete')
    received_invitations=relationship('Invitation', foreign_keys='Invitation.invitee_id', back_populates='invitee', cascade='all, delete')
    def __repr__(self):
        return f'User: {self.name}'


class Invitation(Base):
    __tablename__ = 'invitation'

    id = Column(Integer, primary_key=True)
    invite_code = Column(Integer)
    inviter_id = Column(Integer, ForeignKey('user.id'))
    invitee_id = Column(Integer, ForeignKey('user.id'))
    
    inviter=relationship('User', foreign_keys=[inviter_id], back_populates='sent_invitations')
    invitee=relationship('User', foreign_keys=[invitee_id], back_populates='received_invitations')

    def __repr__(self):
        return f'Invitation: {self.inviter} invited {self.invitee} with {self.invite_code}'


if __name__ == '__main__':
    engine = create_engine('sqlite://')
    Base.metadata.create_all(engine)
    Session = sessionmaker(engine)

    db = Session()

    inviter1 = User(name='inviter1')
    inviter2 = User(name='inviter2')

    invitee1= User(name='invitee1')
    invitee2 = User(name='invitee2')

    invitation1 = Invitation(invite_code=50, inviter=inviter1, invitee=invitee1)
    invitation2 = Invitation(invite_code=20, inviter=inviter2, invitee=invitee2)
    invitation3 = Invitation(invite_code=22, inviter=inviter1, invitee=inviter2)
    invitation4 = Invitation(invite_code=44, inviter=invitee1, invitee=inviter2)
    db.add(inviter1)
    db.add(inviter2)
    db.add(invitee1)
    db.add(invitee2)
    db.commit()

    users = db.query(User).all()
    for user in users:
        print(user)
        print(' sent_invitation: ', user.sent_invitations)
        print(' received_invitation: ', user.received_invitations)
        print()

    invitations = db.query(Invitation).all()
    for invitation in invitations:
        print(invitation)

    db.delete(inviter1)
    db.delete(invitee2)
    db.commit()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM