Python 声明式SQLAlchemy中的物化路径关系

Python 声明式SQLAlchemy中的物化路径关系,python,sqlalchemy,relationship,declarative,materialized-path-pattern,Python,Sqlalchemy,Relationship,Declarative,Materialized Path Pattern,我有一个层次分类模型,其中使用物化路径(每层一个字符)维护层次结构: 在尝试定义“所有子类别”关系时,我遇到了一个问题: sqlalchemy.exc.ArgumentError: Can't determine relationship direction for relationship 'Category.all_subcats' - foreign key columns within the join condition are present in both the parent a

我有一个层次分类模型,其中使用物化路径(每层一个字符)维护层次结构:

在尝试定义“所有子类别”关系时,我遇到了一个问题:

sqlalchemy.exc.ArgumentError: Can't determine relationship direction for
relationship 'Category.all_subcats' - foreign key columns within the join
condition are present in both the parent and the child's mapped tables.
Ensure that only those columns referring to a parent column are marked as
foreign, either via the foreign() annotation or via the foreign_keys argument.
SQLAlchemy很困惑,因为我加入了同一个专栏。我找到的所有示例都在不同的列上进行连接


这种关系可能吗?我想通过此联接进行查询,因此自定义@property是不可接受的。

请使用最新的git master或0.9.5或更高版本的SQLAlchemy。然后:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Element(Base):
    __tablename__ = 'element'

    path = Column(String, primary_key=True)

    related = relationship('Element',
                           primaryjoin=
                                remote(foreign(path)).like(
                                        path.concat('/%')),
                           viewonly=True,
                           order_by=path)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

sess = Session(e)
sess.add_all([
    Element(path="/foo"),
    Element(path="/foo/bar1"),
    Element(path="/foo/bar2"),
    Element(path="/foo/bar2/bat1"),
    Element(path="/foo/bar2/bat2"),
    Element(path="/foo/bar3"),
    Element(path="/bar"),
    Element(path="/bar/bat1")
])

e1 = sess.query(Element).filter_by(path="/foo/bar2").first()
print [e.path for e in e1.related]

请注意,无论您处理的是“后代”还是“应答器”,此模型都使用集合。您希望将
remote()
foreign()
放在一起,以便ORM将其视为一对多。

您应该在上报告类似的问题。我现在正在测试一个补丁。哇,这真是太奇怪了。需要看看我是否可以提交这个。它与SQLAlchemy git master配合使用很好。非常感谢!有没有这样的方法可以在不为每个对象发出单独的SELECT的情况下加载子查询?如果使用subqueryload(),会发生什么情况?它失败了?在这种情况下可能需要更多的修复,发布错误报告。@zzzeek-Hm,似乎
subqueryload()
可以工作,但指定
lazy=“subquery”
则不行。我将提交一份错误报告。
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Element(Base):
    __tablename__ = 'element'

    path = Column(String, primary_key=True)

    related = relationship('Element',
                           primaryjoin=
                                remote(foreign(path)).like(
                                        path.concat('/%')),
                           viewonly=True,
                           order_by=path)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

sess = Session(e)
sess.add_all([
    Element(path="/foo"),
    Element(path="/foo/bar1"),
    Element(path="/foo/bar2"),
    Element(path="/foo/bar2/bat1"),
    Element(path="/foo/bar2/bat2"),
    Element(path="/foo/bar3"),
    Element(path="/bar"),
    Element(path="/bar/bat1")
])

e1 = sess.query(Element).filter_by(path="/foo/bar2").first()
print [e.path for e in e1.related]