簡體   English   中英

如何在 Flask-SQLAlchemy 中同時設置一對多和一對一關系?

[英]How to set one to many and one to one relationship at same time in Flask-SQLAlchemy?

我正在嘗試在 Flask-SQLAlchemy 中同時創建一對一和一對多關系。 我想實現這個:

“一個群組有很多成員和一個管理員。”

這是我所做的:

class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(140), index=True, unique=True)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, server_default=db.func.now())

    members = db.relationship('User', backref='group')
    admin = db.relationship('User', backref='admin_group', uselist=False)

    def __repr__(self):
        return '<Group %r>' % (self.name)


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

    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    admin_group_id = db.Column(db.Integer, db.ForeignKey('group.id'))

    created_at = db.Column(db.DateTime, server_default=db.func.now())

但是我得到一個錯誤:

sqlalchemy.exc.AmbiguousForeignKeysError:無法確定關系 Group.members 上父/子表之間的連接條件 - 有多個外鍵路徑鏈接表。 指定 'foreign_keys' 參數,提供應計為包含對父表的外鍵引用的那些列的列表。

有誰知道如何正確地做到這一點?

您遇到的問題來自於您在類之間定義了兩個鏈接 - 一個用戶有一個group_id(一個外鍵),一個組有一個admin(也是一個外鍵定義) 。 如果從管理字段中刪除外鍵,則連接不再模糊,並且關系有效。 這是我的問題解決方案(使鏈接一對一):

from app import db,app

class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(140), index=True, unique=True)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    admin_id = db.Column(db.Integer) #, db.ForeignKey('user.id'))
    members = db.relationship('User', backref='group')

    def admin(self):
        return User.query.filter_by(id=self.admin_id).first()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    created_at = db.Column(db.DateTime, server_default=db.func.now())

這樣做的一個缺點是組對象沒有你可以使用的簡潔admin成員對象 - 你必須調用函數group.admin()來檢索管理員。 但是,該組可以有許多成員,但只有其中一個可以是管理員。 顯然,沒有DB級別的檢查來確保管理員實際上是該組的成員,但您可以將該檢查添加到setter函數中 - 可能類似於:

# setter method
def admin(self, user):
    if user.group_id == self.id:
        self.admin_id = user.id

# getter method
def admin(self):
    return User.query.filter_by(id=self.admin_id).first()

解決方案是在所有relationship s上指定foreign_keys參數:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)

    group_id = Column(Integer, ForeignKey('groups.id'))
    admin_group_id = Column(Integer, ForeignKey('groups.id'))

class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, primary_key=True)

    members = relationship('User', backref='group', foreign_keys=[User.group_id])
    admin = relationship('User', backref='admin_group', uselist=False, foreign_keys=[User.admin_group_id])

也許考慮在另一個方向的管理關系來實現“一個組有很多成員和一個管理員”:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)

    group_id = Column(Integer, ForeignKey('groups.id'))
    group = relationship('Group', foreign_keys=[group_id], back_populates='members')


class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, primary_key=True)

    members = relationship('User', foreign_keys=[User.group_id], back_populates='group')

    admin_user_id = Column(Integer, ForeignKey('users.id'))
    admin = relationship('User', foreign_keys=[admin_user_id], post_update=True)

請參閱文檔中有關post_update 的說明 當兩個模型相互依賴,相互引用時,這是必要的。

好的,我終於找到了解決這個問題的方法。 多對多關系可以同時與同一兩個表之間的一對多關系共存。

這是代碼:

groups_admins = db.Table('groups_admins',
                         db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
                         db.Column('group_id', db.Integer, db.ForeignKey('group.id'))
                        )


class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(140), index=True, unique=True)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    members = db.relationship('User', backref='group')
    admins = db.relationship('User',
                             secondary=groups_admins,
                             backref=db.backref('mod_groups', lazy='dynamic'),
                             lazy='dynamic')

    def __repr__(self):
        return '<Group %r>' % (self.name)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    created_at = db.Column(db.DateTime, server_default=db.func.now())

我仍然希望有人告訴我如何同時設置一對多和一對一的關系,所以我在這里留下我的答案,不會永遠接受它。

這個鏈接幫我解決了

最重要的是在關系中指定 foreign_keys 值以及主連接

暫無
暫無

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

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