13 Stimmen

Erstellen eines Baums aus selbstreferenziellen Tabellen in SQLalchemy

Ich baue ein grundlegendes CMS in Flask für ein iPhone orientierte Website und ich bin mit ein wenig Mühe mit etwas. Ich habe eine sehr kleine Datenbank mit nur 1 Tabelle (Seiten). Hier ist das Modell:

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)

Wie Sie sehen können, verweisen die Unterseiten einfach auf ein anderes Seitenobjekt in der parent_id Bereich. Was ich versuche, in der Admin-Bedienfeld zu tun ist eine verschachtelte ungeordnete Liste mit allen Seiten in ihren übergeordneten Seiten verschachtelt haben. Ich habe sehr wenig Ahnung, wie man das macht. Alles, was ich denken kann, ist die folgende (die nur funktionieren wird (vielleicht-ich habe es nicht getestet) 2 Ebenen nach unten):

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)

Ich würde sie dann einfach als Liste in der Vorlage formatieren. Wie würde ich diese Arbeit mit potenziell über 10 verschachtelte Seiten machen?

Vielen Dank im Voraus!


EDIT: Ich habe mich ein wenig umgesehen und Folgendes gefunden http://www.sqlalchemy.org/docs/orm/relationships.html#adjacency-list-relationships also habe ich hinzugefügt

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

auf den Grund meines Page Modell. und ich bin auf rekursiv gehen durch alles und fügen Sie es zu einem Baum von Objekten. Ich habe wahrscheinlich keinen Sinn gemacht, aber das ist der beste Weg, wie ich es beschreiben kann


EDIT 2: Ich hatte einen Versuch, eine rekursive Funktion zu machen, um durch alle Seiten zu laufen und ein großes verschachteltes Wörterbuch mit allen Seiten und ihre Kinder zu generieren, aber es hält Python abstürzen, so dass ich denke, es ist nur eine Endlosschleife ... hier ist die Funktion

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

und die Seite, mit der ich es teste:

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

Hat jemand eine Idee?

17voto

estin Punkte 2851

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

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

UPD: Für adjacency_list.py deklaratives Beispiel

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
                )    

Rekursion beheben

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

Verwenden Sie die Abfrage im Beispiel zum rekursiven Abrufen von Daten aus der Datenbank:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X