SQLAlchemy - 关系不仅限于外键

4 投票
1 回答
4149 浏览
提问于 2025-04-15 23:19

我有一个维基数据库的结构,里面有两个主要部分:Page(页面)和Revisions(修订)。每个修订都有一个page_id,它指向对应的页面,还有一个page的关系,表示它关联的页面;每个页面都有一个all_revisions的关系,包含了所有的修订。到这里都很常见。

但我想为页面实现不同的“时代”(epoch):如果一个页面被删除后又重新创建,那么新的修订就会有一个新的epoch。为了帮助找到正确的修订,每个页面都有一个current_epoch字段。现在我想在页面上提供一个revisions的关系,只包含那些与当前时代匹配的修订。

这是我尝试过的:

revisions = relationship('Revision',
    primaryjoin = and_(
        'Page.id == Revision.page_id',
        'Page.current_epoch == Revision.epoch',
    ),
    foreign_keys=['Page.id', 'Page.current_epoch']
)

完整代码(你可以直接运行这个代码)

然而,这总是引发ArgumentError: Could not determine relationship direction for primaryjoin condition ...`的错误,我尝试了所有想到的方法,但都没有成功。

我哪里做错了?这样做是不是不太好?除了用关系,还有什么其他方法可以实现这个功能?

1 个回答

4

试着在创建完两个类之后再安装关系:

Page.revisions = relationship(
    'Revision',
    primaryjoin = (Page.id==Revision.page_id) & \
                    (Page.current_epoch==Revision.epoch),
    foreign_keys=[Page.id, Page.current_epoch],
    uselist=True,
)

顺便说一下,你的测试不太正确:revisions 属性是从数据库加载数据的,但你还没有把它们添加到会话中。

更新:你代码中的问题是 primaryjoin 参数不是字符串,所以它没有被评估。使用字符串作为 primaryjoin 是可以正常工作的:

class Page(Base):
    # [skipped]
    revisions = relationship(
        'Revision',
        primaryjoin = '(Page.id==Revision.page_id) & '\
                        '(Page.current_epoch==Revision.epoch)',
        foreign_keys=[id, current_epoch],
        uselist=True,
    )

撰写回答