Estoy construyendo un CMS básico en un matraz para un sitio orientado a iPhone y estoy teniendo un pequeño problema con algo. Tengo una base de datos muy pequeña con solo 1 tabla (páginas). Aquí está el modelo:Crear un árbol a partir de tablas autorreferenciales en 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)
Como se puede ver, por sub páginas, que acaba de hacer referencia a otra objeto de página en el campo parent_id
. Lo que intento hacer en el panel de administración es tener una lista desordenada anidada con todas las páginas anidadas en sus páginas principales. Tengo muy poca idea de cómo hacer esto. Todo lo que puedo pensar es la siguiente (que sólo funcionará (tal vez, yo no lo he probado) 2 niveles más abajo):
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)
Entonces yo simplemente formatear en una lista en la plantilla. ¿Cómo puedo hacer que esto funcione con potencialmente más de 10 páginas anidadas?
¡Gracias montones por adelantado!
EDIT: He buscado un poco y encontró http://www.sqlalchemy.org/docs/orm/relationships.html#adjacency-list-relationships, por lo que añade
children = db.relationship("Page", backref=db.backref("parent", remote_side=id))
a la parte inferior de mi modelo Page
. y estoy mirando recursivamente a través de todo y agregándolo a un árbol de objetos. Probablemente he hecho ningún sentido, pero esa es la mejor manera en que puedo describirlo
EDIT 2: que tenía un ir a hacer una función recursiva para recorrer automáticamente todas las páginas y generar un diccionario anidada grande con todas las páginas y sus hijos, pero se cae Python, así que creo que es sólo un bucle infinito ... aquí está la función
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
y la página que estoy probando con:
@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)
¿Alguien tiene alguna idea?
Gracias por eso, pero todavía está un poco por encima de mi cabeza. para el segundo enlace, hay una forma de hacerlo con la forma declarativa de definir modelos (¿eso es lo que usa la extensión del matraz para sqlalchemy)? –
@Estin That joinedload_all call especifica "niños" N veces. En este caso 4, entonces el árbol solo recurrirá 4 veces. ¿Hay alguna manera de hacerlo recurrente una cantidad arbitraria de veces? ¿A menos que haya una forma programática de determinarlo fácilmente? –
@Zoran, si planeó trabajos con árboles recurrentes esta no es la mejor opción, formas más poderosas es usar soluciones MPTT como http://sqlalchemy-mptt.readthedocs.org/en/latest/ > A menos que haya una programática forma de determinarlo fácilmente? - Puede almacenar en el nodo raíz su "nivel profundo". – estin