2011-02-12 66 views
7

Tôi có mô hình cơ sở dữ liệu nơi tôi cần mối quan hệ một-nhiều và hai mối quan hệ một-một. Dưới đây là mô hình tôi đã thực hiện, nhưng nó ném lỗiNhiều mối quan hệ tự tham chiếu trong 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 

tôi nhận được lỗi sau bất cứ khi nào tôi cố gắng để làm bất cứ điều gì để các cơ sở dữ liệu

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. 

Điều thực sự kỳ lạ là nó làm việc mà không tiếp theo và cột trước. Có ai biết chuyện gì không?

Trả lời

14

Chủ đề cũ, nhưng vì điều này rất khó hiểu nên tôi sẽ viết nó xuống.
Bạn không cần cột 'prev' riêng biệt, bạn đã có nó như là backref cho 'next'. Ngoài ra, kể từ khi bạn có nhiều phím nước ngoài cùng một mục tiêu, bạn cần phải xác định chính tham gia bằng tay:

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

Một vài lỗi hay chỉ bit của hành vi kỳ lạ tôi nhận thấy:
- Bạn chỉ có thể sử dụng remote_side="Page.id", không phải remote_side=[id] và không phải remote_side=["Page.id"] hoặc không hoạt động (sqlalchemy 0.6.6). Điều này gây phiền nhiễu khi pin xuống.
- Có vẻ như bạn nên luôn sử dụng remote_side với khóa chính, bất kể bạn đang ở phía bên thực tế nào. remote_side="Pages.next_id" sẽ luôn tạo ra một lỗi lạ, ngay cả khi nó có vẻ thích hợp.
- biểu hiện chính bị nhầm lẫn là địa ngục, vì nó không sử dụng bí danh, nhưng đây thực sự là cách chính xác để làm điều đó. Công cụ liên kết biết biểu thức nào cần thay thế bằng tham số (đó là cách quá ngầm và chống lại Zen, btw).

1

Bạn có thể sử dụng 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)) 
Các vấn đề liên quan