2011-02-12 59 views
7

我有一個數據庫模型,我需要一對多關係和兩個一對一關係。下面是我所做的模型,但它引發錯誤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 

我收到以下錯誤,每當我嘗試做任何事情到數據庫

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. 

什麼是真正奇怪的是,它的工作沒有未來和prev列。有人知道什麼是錯的?

回答

14

話題很舊,但是因爲這太混亂了,我會把它寫下來。
您不需要單獨的'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)) 

一對夫婦的錯誤或只是怪異的行爲,我注意到位:
- 您只能使用remote_side="Page.id",而不是remote_side=[id]而不是remote_side=["Page.id"],否則它將不起作用(sqlalchemy 0.6.6)。這很煩人,以確定。
- 看起來你應該總是使用remote_side與主鍵,無論你實際的遠程端是什麼。 remote_side="Pages.next_id"將始終生成一個奇怪的錯誤,即使它看起來合適。
- primaryjoin表達式是混亂的地獄,因爲它不使用別名,但這實際上是做到這一點的正確方法。綁定引擎知道哪個表達式要用一個參數替換(這太隱式了,反對禪,順便說一句)。

1

您可以使用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))