2013-05-20 62 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