SQLAlchemy中的多个自引用关系

Tom*_*oli 7 python sqlalchemy

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

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
Run Code Online (Sandbox Code Playgroud)

每当我尝试对数据库做任何事情时,我都会收到以下错误

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.
Run Code Online (Sandbox Code Playgroud)

真正奇怪的是它没有下一个和上一个列的工作.谁知道什么是错的?

let*_*bee 15

这个话题很古老,但由于这太令人困惑,我会把它写下来.
你不需要单独的'prev'列,你已经将它作为'next'的backref.此外,由于同一目标有多个外键,因此需要手动指定主连接:

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))
Run Code Online (Sandbox Code Playgroud)

我注意到几个错误或一些奇怪的行为:
- 你只能使用remote_side="Page.id",remote_side=[id]而不是remote_side=["Page.id"],或者它不会起作用(sqlalchemy 0.6.6).这很令人讨厌.
- 看起来你总是应该使用remote_side主键,无论你的实际远程是什么.remote_side="Pages.next_id"即使看起来合适,也会产生奇怪的错误.
- primaryjoin表达式令人困惑,因为它不使用别名,但这实际上是正确的方法.绑定引擎知道要用参数替换哪个表达式(这种方式过于隐含并且与Zen,btw相反).


Far*_*eed 5

您可以使用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))
Run Code Online (Sandbox Code Playgroud)