2011-02-12 21 views
7

'da birden çok kendinden referans ilişkisi var Bire çok ilişki ve iki bire bir ilişkiye ihtiyacım olan bir veritabanı modelim var. İşte ben yaptık modeli, ama hataları 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 

i veritabanına şey yapmak için deneyin ne zaman aşağıdaki hatayı alıyorum

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. 

Gerçekten garip bir sonraki olmadan çalıştı yani

atıyor ve prev sütunları. Neyin yanlış olduğunu bilen var mı?

cevap

14

Konu eski, ancak bu çok kafa karıştırıcı olduğundan yazıyorum.
Ayrı 'prev' sütununa ihtiyacınız yok, zaten 'sonraki' için geri adım olarak sahipsiniz. Aynı hedefe birden yabancı anahtarlara sahip beri Ayrıca, sen birincil belirtmek gerekir elle katılır:

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)) 

böcek veya i fark garip davranışların sadece bit bir çift:
- Sadece can remote_side="Page.id", remote_side=[id] değil ve remote_side=["Page.id"] kullanın veya işe yaramaz (sqlalchemy 0.6.6). Bu iğnelemek için can sıkıcıydı.
- Gerçek yanınız ne olduğundan bağımsız olarak, her zaman remote_side'u birincil anahtarla kullanmanız gerektiği anlaşılıyor. remote_side="Pages.next_id", uygun görünse bile her zaman garip bir hata üretecektir.
- primaryjoin ifadesi, takma adları kullanmadığı için cehennem gibi kafa karıştırıcıdır, ancak aslında bunu yapmanın doğru yolu budur. Bağlama altyapısı, hangi ifadenin bir parametreyle değiştirileceğini bilir (bu da çok örtülü ve Zen'e karşı, btw).

1

Sen foreign_keys kullanabilirsiniz:

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))