【问题标题】:SQLAlchemy one-to-many relationship clarificationSQLAlchemy 一对多关系澄清
【发布时间】:2016-03-16 02:15:07
【问题描述】:

阅读 SQLAlchemy 文档后,我仍然不清楚实际上应该如何指定一对多关系。我将分解文档并解释为什么我感到困惑(http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#one-to-many):

一对多关系在子表上放置一个外键 引用父级。

看起来我要在模型上放置一些 Column 属性,该属性将位于关系的“多”端。

relationship() 然后在父级上指定,作为引用由子级表示的项目集合:

这意味着父节点上有一些属性指定参与关系的“多”端的模型。

如果不是因为这样一种情况,我想定义两个一对多关系,关系双方的相同参与者,这对我来说完全有意义。

SQLAlchemy 如何知道关系“多”侧的ForeignKey 列对应于“一”侧的relationship 属性?

【问题讨论】:

    标签: sqlalchemy


    【解决方案1】:

    一对多的关系是这样建立的:

    class Group(Base):
        id = Column(Integer, primary_key=True)
        users = relationship(lambda: User)
    
    class User(Base):
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey(Group.id))
    

    SQLAlchemy 推断您打算使用 parent_id 作为 users 的连接条件,因为它是链接两个表的唯一外键。

    如果你有循环关系:

    class Group(Base):
        id = Column(Integer, primary_key=True)
        owner_id = Column(Integer, ForeignKey("users.id"))
        users = relationship(lambda: User)
    
    class User(Base):
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey(Group.id))
        owned_groups = relationship(Group)
    

    如果你尝试这个,它不会起作用,因为 SQLAlchemy 抱怨它无法推断每个关系使用什么外键。相反,您必须明确告诉它使用什么:

    class Group(Base):
        id = Column(Integer, primary_key=True)
        owner_id = Column(Integer, ForeignKey("users.id"))
        users = relationship(lambda: User, foreign_keys=lambda: User.parent_id)
    
    class User(Base):
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey(Group.id))
        owned_groups = relationship(Group, foreign_keys=Group.owner_id)
    

    一个更完整的反向引用示例:

    class Group(Base):
        id = Column(Integer, primary_key=True)
        owner_id = Column(Integer, ForeignKey("users.id"))
        users = relationship(lambda: User, foreign_keys=lambda: User.parent_id, back_populates="parent")
        owner = relationship(lambda: User, foreign_keys=owner_id, back_populates="owned_groups")
    
    class User(Base):
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey(Group.id))
        owned_groups = relationship(Group, foreign_keys=Group.owner_id, back_populates="owner")
        parent = relationship(Group, foreign_keys=parent_id, back_populates="users")
    

    【讨论】:

    • 感谢您的回答。看来您最近一直在回答我的大部分问题...感谢您的帮助!
    • 有趣的是,SQLAlchemy 会对您的中间示例感到困惑,因为每个类上最多只有一个外键。 (你帮助回答了我的直接问题,所以我会按原样接受答案,但我很好奇你能否详细说明 SQLAlchemy 究竟会混淆什么。)
    • @wheresmycookie SQLAlchemy 无法确定这一点的原因是,不能随意假设所有关系都是一对多的。它们也可以是多对一的。我添加了一个带有 backrefs 的示例,应该可以清楚地说明这一点。在每一侧,实际上有两个关系对应于两个外键中的每一个。想象一下你是 SQLAlchemy。在第二个例子中,你怎么知道owned_groups 不应该是users 关系的另一端(因此使用parent_id 外键)?
    猜你喜欢
    • 1970-01-01
    • 2016-06-15
    • 2021-08-31
    • 2012-06-14
    • 2019-12-06
    • 2014-05-26
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多