I want to create a generic decision tree using SQL Alchemy. That is, each node has zero or more children of any type, and the task is to evaluate some expression using the tree root, which will pass on the logic to the children using extending classes.
I have defined the following base class:
from flask_sqlalchemy import Model, SQLAlchemy, DefaultMeta
from abc import ABCMeta, abstractmethod
from sqlalchemy import Column, Integer, String, Date, Boolean, ForeignKey, Text, Float, Unicode
db = SQLAlchemy(model_class=BaseModel)
class BaseModel(Model):
pass
class ModelABCMeta(DefaultMeta, ABCMeta):
pass
class RuleBaseNode(db.Model, metaclass=ModelABCMeta):
"""Generic base class representing a node in a decision tree"""
id = Column(Integer, primary_key=True)
type = Column(String(50))
parent_node_type = Column(Unicode(255), nullable=True)
parent_node_id = Column(Integer, nullable=True)
parent_node = generic_relationship(parent_node_type, parent_node_id)
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'node'
}
@abstractmethod
def eval(self, input) -> bool:
"""Evaluates an input to a boolean"""
pass
Now the question is how to add an attribute of the node children.
Usually, I would use relationship
with backref
, but I couldn't find anything in the documentation.
I would want such a property:
class RuleBaseNode(db.Model, metaclass=ModelABCMeta):
...
@property
def sub_nodes():
return ...
Now I guess I could implement some sort of the following, but I would guess it won't work with querying an abstract class
def get_sub_nodes(session, node):
session.query(RuleBaseNode).filter(RuleBaseNode.parent_node == node).all()