2013-05-20 2 views
0

http://docs.sqlalchemy.org/ru/latest/orm/extensions/hybrid.html#hybrid-transformersSQLAlchemy의 계층 하이브리드 변환

안녕하세요 동료 SQLAlchemy의 코더를 기반으로! 나는 이전 (N) "속성"을 지원하기 위해 노드 클래스를 확장 할 수 있다면

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) 

그것은 정말 깔끔한 것 :

나는 형식의 데이터가 있습니다. 감사

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

어떤 도움 : 동일한 것

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) 

: 그래서 대신 간단한 조부모의 난으로 사용할 수 있습니다.

편집 : 위와 같은 구조에서 "xpath"를 구현하는 방법은 무엇입니까?

난 트리 경우 :

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

경로 N0221 = 'A'를 노드 [ 'A', 'Ab의', 'S'를

경로 N03 = 노드하기를 ' N ','N ']

목표 : 는 "조상 [X이있는 모든 노드를 찾기, Y, ...] 어디서든 계층 구조에서"인수에 대한 예를 들어 쿼리 (['S ',' N ']) 노드를 반환합니다 :

N022

N0221

다음 그들의 경로이기 때문에 같이

N022 - 경로 = A, S, N

N0221- 경로 = A, S, N, N

위는 node.name뿐 아니라 일치하도록 일반화 될 수 있습니다.

그것은 다음과 같이 involed 수 있습니다 : (제안)

답변

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

너무 감사합니다 어떤 도움

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

또는 이와 유사한

감사합니다! – paroxyzm