2011-02-04 2 views
11

저는 iPhone 지향 사이트 용 플라스크에 기본 CMS를 구축 중이며 약간 문제가 있습니다. 나는 단 하나의 테이블 (페이지)을 가진 아주 작은 데이터베이스를 가지고있다. 여기 모델은 : 당신이 볼 수 있듯이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) 

는, 페이지를 서브를 들어, 그들은 단지 parent_id 분야에서 다른 페이지 개체를 참조. 관리자 패널에서 수행하려는 작업은 상위 페이지에 중첩 된 모든 페이지가있는 중첩되지 않은 목록이 있습니다. 나는이 일을하는 법을 거의 모른다.

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) 

내가 그럼 그냥 템플릿리스트로 포맷 것입니다 : 내가 생각할 수있는 모든은 (에만 작동합니다 (아마도-I는 그것을 테스트하지 않은 경우) 아래 2 단계) 다음이다. 잠재적으로 10 개가 넘는 중첩 페이지로이 작업을 어떻게 만들 수 있습니까?

미리 감사드립니다.


편집 : 내가 조금 둘러 보았다 및 http://www.sqlalchemy.org/docs/orm/relationships.html#adjacency-list-relationships을 발견, 그래서 내 Page 모델의 바닥에

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

을 추가했습니다. 재귀 적으로 모든 것을 거쳐 오브젝트의 트리에 추가하는 것을보고 있습니다. 아마 말도하지했지만, 그게 내가이 그것을


편집을 설명 할 수있는 가장 좋은 방법이다 : 나는 모든 페이지를 실행하고 큰 중첩 된 사전을 생성하는 재귀 함수를 만들기에 이동했다

@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) 
0 : 모든 페이지와 자녀,하지만 파이썬 충돌 계속 함께 그래서 내가 여기에 기능

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 

그리고 난 그것을 테스트하고있어 페이지의 ... 그냥 무한 루프 생각

누구에게 아이디어가 있습니까?

답변

14

http://sqlamp.angri.ru/index.html

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

UPD에서 봐 : EXA에 adjacency_list.py 선언 예를 들어

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 
       )  

수정 재귀

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 

를 사용하여 쿼리 재귀 적으로 데이터를 가져 오기위한 mple :

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

고마워요.하지만 고맙습니다. 두 번째 링크에서 모델을 정의하는 선언적 기본 방법으로 그렇게 할 여지가있다 (sqlalchemy의 플라스크 확장이 사용하는 것)? –

+0

@Estin That joinedall_all 호출은 "children"을 N 번 지정합니다. 이 경우 4, 그래서 트리는 4 회만 반복됩니다. 임의의 시간에 반복 재생할 수있는 방법이 있습니까? 프로그램 방식으로 쉽게 결정할 수 없다면? –

+1

@ Zoran, 나무 재귀 작업을 계획한다면 이것이 최선의 선택이 아닙니다. http://sqlalchemy-mptt.readthedocs.org/en/latest/와 같은 MPTT 솔루션을 사용하는 것이 더 효과적입니다. > 프로그래밍 방식이없는 경우 그것을 쉽게 결정하는 방법? - 루트 노드에 "깊은 수준"을 저장할 수 있습니다. – estin