我正在尝试基于此博客文章实现闭包表,它具有使用 sqlalchemy 的闭包表的唯一完整和功能实现,我在这里链接只是为了给予信任,但我想替换children_table
(见下面的代码示例)depth
在closure_table
. _
问题是我真的不知道如何为这个新列设置任何值,因为predecessor
和successor
列是通过 -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)
(我删除了子表的输出,因为子表将完全从代码中删除,因为它不再需要了。)
粗体箭头表示子表,虚线箭头表示闭合表。