2013-05-20 57 views
0

基于http://docs.sqlalchemy.org/ru/latest/orm/extensions/hybrid.html#hybrid-transformersSQLalchemy分层混合转换

你好同事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) 

这将是真的整洁如果我能扩展节点类,以支持前身(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', '抗体']

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

目标: “查找其祖先有[X的所有节点,Y,...]随时随地其层次结构” 为参数例如查询([ 'S',' N'])将返回节点:

N022

N0221

,因为它们的路径如下:

N022 - 路径= A,S,N

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

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

它可以involed如下:(提案)

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

或类似的东西

感谢所有帮助

回答

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)) 
+0

太感谢你了! – paroxyzm