【问题标题】:Multiple self referential relationships in SQLAlchemySQLAlchemy 中的多个自引用关系
【发布时间】:2017-08-15 21:15:30
【问题描述】:

我有一个数据库模型,我需要一个一对多关系和两个一对一关系。这是我制作的模型,但它会抛出错误

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    children    = relationship("Page", backref=backref("parent", remote_side=id))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", backref=backref("prev", remote_side=id, uselist=False))

    prev_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    prev        = relationship("Page", backref=backref("next", remote_side=id, uselist=False))

    def __init__(self, title, content, parent_id=None, next_id=None, prev_id=None):
        self.title = title
        self.content = content
        self.parent_id = parent_id
        self.next_id = next_id
        self.prev_id = prev_id

    def __repr__(self):
        return '<Page "%r">' % self.title

每当我尝试对数据库执行任何操作时都会收到以下错误

ArgumentError: Could not determine join condition between parent/child tables on relationship Page.children. Specify a 'primaryjoin' expression. If 'secondary' is present, 'secondaryjoin' is needed as well.

真正奇怪的是,它在没有 next 和 prev 列的情况下工作。有谁知道怎么回事?

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    这个话题很老了,但是因为这太令人困惑了,所以我会写下来。
    您不需要单独的“上一个”列,您已经将它作为“下一个”的反向引用。 此外,由于您对同一个目标有多个外键,因此您需要手动指定主连接:

    class Page(Base):
        __tablename__ = 'pages'
        id          = Column(Integer, primary_key=True)
        title       = Column(String(100), nullable=False)
        content     = Column(Text, nullable=False)
    
        parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
        parent      = relationship("Page",
                        primaryjoin=('pages.c.id==pages.c.parent_id'),
                        remote_side='Page.id',
                        backref=backref("children" ))
    
        next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
        next        = relationship("Page", 
                        primaryjoin=('pages.c.next_id==pages.c.id'),
                        remote_side='Page.id', 
                        backref=backref("prev", uselist=False))
    

    我注意到一些错误或只是一些奇怪的行为:
    - 只能使用remote_side="Page.id",不能使用remote_side=[id],也不能使用remote_side=["Page.id"],否则将无法使用(sqlalchemy 0.6.6)。这很烦人。
    - 似乎您应该始终使用带有主键的remote_side,无论您实际的远程端是什么。 remote_side="Pages.next_id" 总是会产生一个奇怪的错误,即使它看起来很合适。
    - primaryjoin 表达式令人困惑,因为它不使用别名,但这实际上是正确的方法。绑定引擎知道用参数替换哪个表达式(顺便说一句,这太隐晦了,不符合 Zen)。

    【讨论】:

      【解决方案2】:

      你可以使用foreign_keys:

      class Page(Base):
          __tablename__ = 'pages'
          id          = Column(Integer, primary_key=True)
          title       = Column(String(100), nullable=False)
          content     = Column(Text, nullable=False)
      
          parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
          parent      = relationship("Page",
                          foreign_keys=[parent_id],
                          remote_side=[id],
                          backref=backref("children" ))
      
          next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
          next        = relationship("Page", 
                          foreign_keys=[next_id],
                          remote_side=[id], 
                          backref=backref("prev", uselist=False))
      

      【讨论】:

        猜你喜欢
        • 2011-05-09
        • 1970-01-01
        • 2023-03-17
        • 2018-10-02
        • 1970-01-01
        • 2011-07-20
        • 1970-01-01
        • 2021-05-31
        • 2014-09-30
        相关资源
        最近更新 更多