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.
奇怪的是,在没有“下一个”和“上一个”这两列的时候,它是可以正常工作的。有人知道问题出在哪里吗?
2 个回答
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))
22
这个话题虽然老旧,但因为实在让人困惑,所以我还是写下来吧。
你不需要单独的“prev”列,因为你已经有了作为“next”的反向引用。
另外,由于你有多个外键指向同一个目标,你需要手动指定主连接。
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 表达式让人困惑,因为它不使用别名,但这其实是正确的做法。绑定引擎知道哪个表达式需要替换成参数(这点太隐晦了,和简单明了的原则有点背道而驰)。