4

我正在尝试基于此博客文章实现闭包表,它具有使用 sqlalchemy 的闭包表的唯一完整和功能实现,我在这里链接只是为了给予信任,但我想替换children_table(见下面的代码示例)depthclosure_table. _

问题是我真的不知道如何为这个新列设置任何值,因为predecessorsuccessor列是通过 -class 中指定的关系自动设置的Category,我想不出有意义的搜索引擎关键字来找到线索在互联网。我试图在 sqlalchemy 文档中找到解决方案已经有一段时间了,但是很难识别适用于这个特定任务的相关部分。

如果某个 sqlalchemy 专家可以教我必须以哪种方式更改代码中的哪些部分,或者至少提示我到文档中的正确章节,这样我就可以继续尝试以更清晰的重点自己弄清楚它,那将是非常棒的。

为了澄清我想知道的内容:有类似这样的答案,它显示了如何在 SQL 中计算和设置深度值:

INSERT INTO closure_tree_path (ancestor, descendant, depth)
SELECT ancestor, '{$node_id}', depth+1 FROM closure_tree_path
WHERE descendant = '{$parent_id}'
UNION ALL SELECT '{$node_id}', '{$node_id}', 0;

但最重要的问题是必须如何修改我的代码才能首先为depth-column 设置值 - 努力实现功能齐全的深度列的目标。如果有人想出了完整的解决方案,我绝对不会介意... :-)

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Table
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker


engine = create_engine('sqlite:///:memory:', echo=False)

Base = declarative_base()


children_table = Table('edges', Base.metadata,
    Column('predecessor', Integer,
           ForeignKey('categories.id'), primary_key=True),
    Column('successor', Integer,
           ForeignKey('categories.id'), primary_key=True))


closure_table = Table('paths', Base.metadata,
    Column('predecessor', Integer,
           ForeignKey('categories.id'), primary_key=True),
    Column('successor', Integer,
           ForeignKey('categories.id'), primary_key=True),
    Column('depth', Integer))


class Category(Base):
    __tablename__ = 'categories'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False, unique=True)

    children = relationship('Category', backref='predecessors',
        secondary=children_table,
        primaryjoin=id == children_table.c.predecessor,
        secondaryjoin=id == children_table.c.successor)

    descendants = relationship('Category', backref='after',
        secondary=closure_table,
        primaryjoin=id == closure_table.c.predecessor,
        secondaryjoin=id == closure_table.c.successor)

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return '%r, %r, %r, %r' % (self.id, self.name, [x.id for x in self.descendants], [x.id for x in self.children])

    def add_successor(self, other):
        if other in self.children:
            return
        self.children.append(other)
        self.descendants.append(other)
        for descendent in other.descendants:
            if descendent not in self.descendants:
                self.descendants.append(descendent)
        for ancestor in self.after:
            if ancestor not in other.after:
                other.after.append(ancestor)


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
sess = Session()


# add test data
a = Category("A")
b = Category("B")
c = Category("C")
d = Category("D")
e = Category("E")
f = Category("F")
g = Category("G")
h = Category("H")
a.add_successor(b)
a.add_successor(c)
b.add_successor(d)
b.add_successor(e)
c.add_successor(f)
c.add_successor(g)
f.add_successor(h)
sess.add(a)


print("Category Table:")
for c in sess.query(Category).all(): print(c)
print("\nChildren Table:")
for c in sess.query(children_table).all(): print(c)
print("\nClosure Table:")
for c in sess.query(closure_table).all(): print(c)

closure_table我的运行示例中已经包含一个附加列depth,但到目前为止它只包含None

Category Table:
1, 'A', [2, 5, 3, 4, 6, 8, 7], [2, 5]
2, 'B', [3, 4], [3, 4]
3, 'D', [], []
4, 'E', [], []
5, 'C', [6, 8, 7], [6, 8]
6, 'F', [7], [7]
7, 'H', [], []
8, 'G', [], []

Children Table:
(5, 6)
(1, 2)
(5, 8)
(1, 5)
(6, 7)
(2, 3)
(2, 4)

Closure Table:
(5, 6, None)
(1, 6, None)
(1, 2, None)
(5, 8, None)
(1, 8, None)
(1, 5, None)
(6, 7, None)
(5, 7, None)
(1, 7, None)
(2, 3, None)
(1, 3, None)
(2, 4, None)
(1, 4, None)

但是,所需的输出将是:

Category Table:
1, 'A', [2, 5, 3, 4, 6, 8, 7], [2, 5]
2, 'B', [3, 4], [3, 4]
3, 'D', [], []
4, 'E', [], []
5, 'C', [6, 8, 7], [6, 8]
6, 'F', [7], [7]
7, 'H', [], []
8, 'G', [], []

Closure Table:
(5, 6, 1)
(1, 6, 2)
(1, 2, 1)
(5, 8, 1)
(1, 8, 2)
(1, 5, 1)
(6, 7, 1)
(5, 7, 2)
(1, 7, 3)
(2, 3, 1)
(1, 3, 2)
(2, 4, 1)
(1, 4, 2)

(我删除了子表的输出,因为子表将完全从代码中删除,因为它不再需要了。)

对应的图表如下所示: 粗体箭头表示子表,虚线箭头表示闭合表。

粗体箭头表示子表,虚线箭头表示闭合表。

4

0 回答 0