このブログ投稿に基づいてクロージャー テーブルを実装しようとしています。これは、sqlalchemy を使用したクロージャー テーブルの唯一の完全かつ機能的な実装を特徴としており、信用を与えるためにここにリンクしていますが、置き換えたいですchildren_table
(以下のコード例を参照)。内にdepth
-column を使用しclosure_table
ます。
問題は、この新しい列に値を設定する方法が本当にわからないことです.and 列は -class内で指定された関係を介して自動的に設定され、手がかりを見つけるための意味のある検索エンジンのキーワードが思い浮かびません。インタネットの中には。かなり長い間、sqlalchemy ドキュメントで解決策を見つけようとしましたが、この特定のタスクに適用される関連部分を認識するのは困難です。predecessor
successor
Category
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;
しかし、最も重要な問題は、最初に -column に値を設定できるようにコードをどのように変更する必要があるかということですdepth
- 完全に機能する深さ列の目標に向けて取り組んでいます。誰かが完全な解決策を思いついたとしても、私は間違いなく気にしません... :-)
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)
(children テーブルはもう必要ないため、コードから完全に削除されるため、children テーブルの出力を削除しました。)
太字の矢印は子テーブルを視覚化し、破線の矢印はクロージャー テーブルを表します。