1313from sqlalchemy .orm import backref , relationship , object_session
1414from sqlalchemy .orm .session import Session
1515from sqlalchemy .ext .declarative import declared_attr
16+ from sqlalchemy .ext .hybrid import hybrid_method
1617
1718from .events import _get_tree_table
1819
@@ -72,7 +73,7 @@ def parent_id(cls):
7273 if not pk .name :
7374 pk .name = cls .get_pk_name ()
7475
75- return Column ("parent_id" , Integer ,
76+ return Column ("parent_id" , pk . type ,
7677 ForeignKey ('%s.%s' % (cls .__tablename__ , pk .name ),
7778 ondelete = 'CASCADE' ))
7879
@@ -99,6 +100,30 @@ def right(cls):
99100 def level (cls ):
100101 return Column ("level" , Integer , nullable = False , default = 0 )
101102
103+ @hybrid_method
104+ def is_ancestor_of (self , other , inclusive = False ):
105+ """ class or instance level method which returns True if self is ancestor (closer to root) of other else False.
106+ Optional flag `inclusive` on whether or not to treat self as ancestor of self.
107+
108+ For example see:
109+
110+ * :mod:`sqlalchemy_mptt.tests.cases.integrity.test_hierarchy_structure`
111+ """
112+ if inclusive :
113+ return (self .tree_id == other .tree_id ) & (self .left <= other .left ) & (other .right <= self .right )
114+ return (self .tree_id == other .tree_id ) & (self .left < other .left ) & (other .right < self .right )
115+
116+ @hybrid_method
117+ def is_descendant_of (self , other , inclusive = False ):
118+ """ class or instance level method which returns True if self is descendant (farther from root) of other else False.
119+ Optional flag `inclusive` on whether or not to treat self as descendant of self.
120+
121+ For example see:
122+
123+ * :mod:`sqlalchemy_mptt.tests.cases.integrity.test_hierarchy_structure`
124+ """
125+ return other .is_ancestor_of (self , inclusive )
126+
102127 def move_inside (self , parent_id ):
103128 """ Moving one node of tree inside another
104129
@@ -247,9 +272,7 @@ def _drilldown_query(self, nodes=None):
247272 table = self .__class__
248273 if not nodes :
249274 nodes = self ._base_query_obj ()
250- return nodes .filter (table .tree_id == self .tree_id )\
251- .filter (table .left >= self .left )\
252- .filter (table .right <= self .right )
275+ return nodes .filter (self .is_ancestor_of (table , inclusive = True ))
253276
254277 def drilldown_tree (self , session = None , json = False , json_fields = None ):
255278 """ This method generate a branch from a tree, begining with current
@@ -309,9 +332,7 @@ def path_to_root(self, session=None):
309332 """
310333 table = self .__class__
311334 query = self ._base_query_obj (session = session )
312- query = query .filter (table .tree_id == self .tree_id )\
313- .filter (table .left <= self .left )\
314- .filter (table .right >= self .right )
335+ query = query .filter (table .is_ancestor_of (self , inclusive = True ))
315336 return self ._base_order (query , order = desc )
316337
317338 @classmethod
0 commit comments