SQLAlchemy使用关联代理对象对树结构进行排序以进行定位

时间:2014-09-02 12:19:00

标签: python sqlalchemy associations relationship

我试图创建一个简单的任务树结构。任务可以具有状态(完成:布尔)和标题(标题:字符串)和任意数量的子任务(任务:任务[])。我成功地设法创建了一个Task对象和关联代理对象PositionedTask。父/子关系似乎有效,尽管定位未被使用。

这是我到目前为止所获得的代码:

import sys

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import Boolean
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import backref
from sqlalchemy.orm import Session
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.orderinglist import ordering_list

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()


class Task(Base):
    __tablename__ = 'tasks'

    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    done = Column(Boolean, nullable=True, default=False)

    parent_id = Column(Integer, ForeignKey('tasks.id'))
    tasks = association_proxy('tasks_positioned', 'task')

    def __init__(self, title=None, done=False):
        self.title = title
        self.done = done

    def __repr__(self):
        return '<Task #{0} \'{1}\' done={2}>'.format(self.id, self.title, self.done)



class PositionedTask(Base):
    __tablename__ = 'tasks_subtasks'
    parent_id = Column(Integer, ForeignKey('tasks.id'), primary_key=True)
    task_id = Column(Integer, ForeignKey('tasks.id'), primary_key=True)
    position = Column(Integer, default=0, nullable=False)

    parent = relationship(Task, foreign_keys='PositionedTask.parent_id', backref=backref('tasks_positioned', cascade='all, delete-orphan'))
    task = relationship(Task, foreign_keys='PositionedTask.task_id')

    def __init__(self, task=None, parent=None, position=None):
        self.task = task
        self.parent = parent
        self.position = position

    def __repr__(self):
        return '<PositionedTask parent=\'{0}\' task=\'{1}\' position={2}>'.format(
            self.parent.title, self.task.title, self.position
        )


def main(argv=sys.argv):
    engine = create_engine('sqlite:///test.db', echo=False)
    Base.metadata.create_all(engine)
    session = Session(engine)

    task = Task('Parent')
    child1 = Task('Child #1', done=True)
    child2 = Task('Child #2')
    grandchild1 = Task('GrandChild #1')

    child1.tasks.append(grandchild1)
    task.tasks.append(child1)
    task.tasks.append(child2)

    session.add(task)
    session.commit()

    task = session.query(Task).filter(Task.id==1).first()
    print task
    for st in task.tasks:
        print st
    for pst in task.tasks_positioned:
        print pst

if __name__ == '__main__':
    main()

当前应用程序的输出是:

<Task #1 'Parent' done=False>
<Task #2 'Child #1' done=True>
<Task #4 'Child #2' done=False>
<PositionedTask parent='Parent' task='Child #1' position=0>
<PositionedTask parent='Parent' task='Child #2' position=0>

如何将sqlalchemy.ext.orderinglist.ordering_list与此代码混合以自动定位子任务?

1 个答案:

答案 0 :(得分:0)

只需修改backref关系的PositionedTask.parent部分,即可:

parent = relationship(
    Task,
    foreign_keys='PositionedTask.parent_id',
    backref=backref(
        'tasks_positioned',
        order_by ="PositionedTask.position", # @new:
        collection_class=ordering_list('position'), # @new:
        cascade='all, delete-orphan'),
    )