【问题标题】:SQLalchemy hierarchical hybrid-transformationSQLalchemy 分层混合转换
【发布时间】:2013-06-16 01:49:21
【问题描述】:

基于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]/*')

或类似的东西

感谢您的帮助

【问题讨论】:

    标签: python sqlalchemy hierarchical


    【解决方案1】:
    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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多