基于http://docs.sqlalchemy.org/ru/latest/orm/extensions/hybrid.html#hybrid-transformers
Hello 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)“property”,那将非常简洁。 因此,我可以将其用作:
而不是简单的祖父母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]/*')
或类似的东西
感谢您的帮助
答案 0 :(得分: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))