0

基于http://docs.sqlalchemy.org/ru/latest/orm/extensions/hybrid.html#hybrid-transformers

你好,sqlalchemy 程序员们!

我有一个表格数据:

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.ext.hybrid import Comparator

class GrandparentTransformer(Comparator):
    def operate(self, op, other):
        def transform(q):
            cls = self.__clause_element__()
            parent_alias = aliased(cls)
            return q.join(parent_alias, cls.parent).\
                        filter(op(parent_alias.parent, other))
        return transform

Base = declarative_base()

class Node(Base):
    __tablename__ = 'node'
    id =Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('node.id'))
    parent = relationship("Node", remote_side=id)

    @hybrid_property
    def grandparent(self):
        return self.parent.parent

    @grandparent.comparator
    def grandparent(cls):
        return GrandparentTransformer(cls)

如果我可以扩展 Node 类以支持前任(n)“属性”,那就太好了。这样我就可以将它用作:

node.predecessor(0) == node
node.predecessor(1) == node.parent
node.predecessor(2) == node.parent.parent == node.grandparent
(...etc...)

session.query(Node).with_transformation(Node.grandparent.join).filter(Node.grandparent==None)

将等于:

session.query(Node).with_transformation(Node.predecessor(2).join).filter(Node.predecessor(2)==None)

任何帮助表示赞赏。

编辑: 如何在上面的结构上实现“xpath”?

如果我有一棵树:

N0(n='A')
 -N01(n='S')
 -N02(n='S')
   -N021(n='V')
   -N022(n='N')
     -N0221(n='N')
 -N03(n='Ab')

节点 N03 的路径 = ['A','Ab']

节点 N0221 的路径 = ['A','S','N','N']

目标: “查找其祖先在其层次结构中的任何位置具有 [X,Y,...] 的所有节点” 例如查询参数 (['S','N']) 将返回节点:

N022

N0221

因为他们的路径如下:

N022 - 路径=A,S,N

N0221-路径=A,S,N,N

以上可以概括为不仅通过 node.name 匹配。

可涉及如下:(建议)

session.query(Node).xpath('//[@name=S]/[@name=N]/*')

或类似的东西

谢谢你的帮助

4

1 回答 1

0
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, aliased
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from sqlalchemy.ext.hybrid import Comparator, hybrid_property, hybrid_method

class GrandparentTransformer(Comparator):
    def __init__(self, expression, levels):
        self.expression = expression
        self.levels = levels

    def operate(self, op, other):
        def transform(q):
            cls = self.__clause_element__()
            for i in xrange(self.levels):
                parent_alias = aliased(cls)
                q = q.join(parent_alias, cls.parent).\
                            filter(op(parent_alias.parent, other))
                cls = parent_alias
            return q
        return transform

Base = declarative_base()

class Node(Base):
    __tablename__ = 'node'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('node.id'))
    parent = relationship("Node", remote_side=id)

    @hybrid_property
    def grandparent(self):
        return self.predecessor(2)

    @hybrid_method
    def predecessor(self, n):
        if n == 0:
            return self
        else:
            return self.parent.predecessor(n - 1)

    @predecessor.expression
    def predecessor(cls, n):
        return GrandparentTransformer(cls, n)

n1, n2, n3, n4 = Node(), Node(), Node(), Node()
n1.parent = n2
n2.parent = n3
n3.parent = n4

assert n1.predecessor(2) is n3 is n1.grandparent
assert n1.predecessor(1) is n2
assert n1.predecessor(0) is n1

session = Session()

print session.query(Node).with_transformation(Node.grandparent == Node(id=5))

print session.query(Node).with_transformation(Node.predecessor(2) == Node(id=5))

print session.query(Node).with_transformation(Node.predecessor(5) == Node(id=5))
于 2013-05-20T21:03:06.723 回答