2011-02-04 5 views
11

Buduję podstawowy CMS w kolbie dla strony zorientowanej na iPhone'a i mam z tym trochę problemów. Mam bardzo małą bazę danych z tylko jednym stołem (strony). Oto model:Tworzenie drzewa z samodzielnych tabel referencyjnych w SQLalchemy

class Page(db.Model): 
    __tablename__ = 'pages' 
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(100), nullable=False) 
    content = db.Column(db.Text, nullable=False) 
    parent_id = db.Column(db.Integer, db.ForeignKey("pages.id"), nullable=True) 

Jak widać, do podstron, po prostu odwołać się inny obiekt strony w polu parent_id. W panelu administracyjnym próbuję wykonać zagnieżdżoną listę nieuporządkowaną z wszystkimi stronami zagnieżdżonymi na stronach nadrzędnych. Nie mam zielonego pojęcia, jak to zrobić. Wszystko, co mogę myśleć jest następujący (które działa tylko (może, nie mam go testowane) 2 poziomy w dół):

pages = Page.query.filter_by(parent_id=None) 
for page in pages: 
    if Page.query.filter_by(parent_id=page.id): 
     page.sub_pages = Page.query.filter_by(parent_id=page.id) 

bym to po prostu sformatować go na liście w szablonie. Jak mogę to zrobić z potencjalnie ponad 10 zagnieżdżonymi stronami?

Dzięki temu stosy z góry!


EDIT: Mam rozejrzał się trochę i znaleźć http://www.sqlalchemy.org/docs/orm/relationships.html#adjacency-list-relationships, więc dodałem

children = db.relationship("Page", backref=db.backref("parent", remote_side=id)) 

do głębi Page modelu. i patrzę na rekursywne przeglądanie wszystkiego i dodawanie go do drzewa obiektów. Ja chyba nie ma sensu, ale to najlepszy sposób mogę opisać


EDIT 2: miałem iść na dokonanie rekurencyjną funkcję uruchamiania poprzez wszystkich stron i generują duży zagnieżdżonego słownika ze wszystkich stron i ich dzieci, ale zawiesza się Pythona, więc myślę, że to jest po prostu nieskończona pętla ... oto funkcja

def get_tree(base_page, dest_dict): 
    dest_dict = { 'title': base_page.title, 'content': base_page.content } 
    children = base_page.children 
    if children: 
     dest_dict['children'] = {} 
     for child in children: 
      get_tree(base_page, dest_dict) 
    else: 
     return 

a strona jestem sprawdzając je za pomocą:

@app.route('/test/') 
def test(): 
    pages = Page.query.filter_by(parent_id=None) 
    pages_dict = {} 
    for page in pages: 
     get_tree(page, pages_dict) 
    return str(pages_dict) 

ktoś ma jakieś pomysły?

Odpowiedz

14

Spójrz na http://sqlamp.angri.ru/index.html

lub http://www.sqlalchemy.org/trac/browser/examples/adjacency_list/adjacency_list.py

UPD: Dla adjacency_list.py deklaratywnej przykład

from sqlalchemy.ext.declarative import declarative_base 
Base = declarative_base(metadata=metadata) 

class TreeNode(Base): 

    __tablename__ = 'tree' 

    id = Column(Integer, primary_key=True) 
    parent_id = Column(Integer, ForeignKey('tree.id')) 
    name = Column(String(50), nullable=False) 

    children = relationship('TreeNode', 

         # cascade deletions 
         cascade="all", 

         # many to one + adjacency list - remote_side 
         # is required to reference the 'remote' 
         # column in the join condition. 
         backref=backref("parent", remote_side='TreeNode.id'), 

         # children will be represented as a dictionary 
         # on the "name" attribute. 
         collection_class=attribute_mapped_collection('name'), 
        ) 

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

    def append(self, nodename): 
     self.children[nodename] = TreeNode(nodename, parent=self) 

    def __repr__(self): 
     return "TreeNode(name=%r, id=%r, parent_id=%r)" % (
        self.name, 
        self.id, 
        self.parent_id 
       )  

Fix rekurencji

def get_tree(base_page, dest_dict): 
    dest_dict = { 'title': base_page.title, 'content': base_page.content } 
    children = base_page.children 
    if children: 
     dest_dict['children'] = {} 
     for child in children: 
      get_tree(child, dest_dict) 
    else: 
     return 

Wykorzystanie zapytań w EXA mple dla rekurencyjnego pobierania danych z db:

# 4 level deep 
node = session.query(TreeNode).\ 
         options(joinedload_all("children", "children", 
               "children", "children")).\ 
         filter(TreeNode.name=="rootnode").\ 
         first() 
+0

Dziękuję za to, ale wciąż jest trochę ponad moją głową. dla drugiego linku jest tam wak, aby to zrobić z deklaratywną podstawową metodą definiowania modeli (to jest to, czego używa rozszerzenie kostki do sqlalchemy)? –

+0

@Estin To joinload_all call określa "dzieci" N razy. W tym przypadku 4, a więc drzewo będzie rekursować tylko 4 razy. Czy istnieje sposób na jej powtarzanie dowolną ilość razy? Chyba że istnieje programowy sposób na łatwe określenie? –

+1

@Zoran, jeśli zaplanowałeś pracę z rekurencjami drzew, nie jest to najlepszy wybór, bardziej wydajne jest używanie rozwiązań MPTT, takich jak http://sqlalchemy-mptt.readthedocs.org/en/latest/ > O ile nie jest programowany sposób na łatwe określenie? - Możesz przechowywać na głównym węźle jego "głęboki poziom". – estin

Powiązane problemy