天天看點

python 樹結構 sqlalchemy_從SQLalchemy中的自引用表建立樹

python 樹結構 sqlalchemy_從SQLalchemy中的自引用表建立樹

I'm building a basic CMS in flask for an iPhone oriented site and I'm having a little trouble with something. I have a very small database with just 1 table (pages). Here's the model:

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)

As you can see, for sub pages, they just reference another page object in the parent_id field. What I'm trying to do in the admin panel is have a nested unordered list with all the pages nested in their parent pages. I have very little idea on how to do this. All i can think of is the following (which will only work (maybe—I haven't tested it) 2 levels down):

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 would then just format it into a list in the template. How would I make this work with potentially over 10 nested pages?

Thanks heaps in advance!

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

to the bottom of my Page model. and I'm looking at recursively going through everything and adding it to a tree of objects. I've probably made no sense, but that's the best way I can describe it

EDIT 2: I had a go at making a recursive function to run through all the pages and generate a big nested dictionary with all the pages and their children, but it keeps crashing python so i think it's just an infinite loop... here's the function

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

and the page i'm testing it with:

@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)

anyone got any ideas?

解決方案

UPD: For adjacency_list.py declarative example

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 recursion

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

Use query in example for recursive fetch data from db:

# 4 level deep

node = session.query(TreeNode).\

options(joinedload_all("children", "children",

"children", "children")).\

filter(TreeNode.name=="rootnode").\

first()