SQLAlchemy和过滤多态查询

时间:2012-11-25 23:34:52

标签: inheritance sqlalchemy polymorphic-associations flask-sqlalchemy

我的课程NodeLeaf (Node)如下所示:

class Node (db.Model):
    __mapper_args__ = {'polymorphic_identity':'node', 'polymorphic_on':'type'}
    id = db.Column (db.Integer, primary_key=True)
    type = db.Column ('type', db.String (16))

    root_id = db.Column (db.Integer, db.ForeignKey (id))
    nodes = db.relationship ('Node',
        cascade='all', lazy='dynamic',
        primaryjoin='Node.root_id==Node.id',
        backref=db.backref('root', remote_side=id))
    leafs = db.relationship ('Leaf',
        cascade='all', lazy='dynamic',
        primaryjoin='Leaf.root_id==Node.id')

    def __init__ (self, root):
        self.root = root

class Leaf (Node):
    __mapper_args__ = {'polymorphic_identity': 'leaf'}
    leaf_id = db.Column (db.Integer, db.ForeignKey ('node.id'), primary_key=True)

    def __init__ (self, root):
        super (Leaf, self).__init__ (root)

具有以下属性(摘自我的测试):

def test_polymorphic (self):
    base_node, leaf_of_base, node_of_base, leaf_of_node = self.create ()
    self.commit ([base_node, leaf_of_base, node_of_base, leaf_of_node])

    leaf, node = base_node.nodes.all ()

    self.assertEqual (type (leaf), Leaf)
    self.assertTrue (isinstance (leaf, Node))
    self.assertTrue (isinstance (leaf, Leaf))

    self.assertEqual (type (node), Node)
    self.assertTrue (isinstance (node, Node))
    self.assertFalse (isinstance (node, Leaf))

所以Node.nodes 包含叶子对象(这就是我想要的),而Node.leafs会导致叶子对象(这也很好)

现在,我想介绍一下我喜欢的Node.nodes_except_leafs

class Node (db.Model):
    ...
    nodes_except_leafs = property (lambda self: self.nodes.filter_by (type='node'))

这实际上有效,但我不认为这是最好的解决方案,因为使用这种方法,我会错过一个例如以下类型:

class NodeEx (Node):
    __mapper_args__ = {'polymorphic_identity': 'nodeex'}
    nodex_id = db.Column (db.Integer, db.ForeignKey ('node.id'), primary_key=True)

    def __init__ (self, root):
        super (NodeEx, self).__init__ (root)

由于Node.nodes.filter_by (type='node')会错过NodeEx的所有NodeEx.type == 'nodeex'个对象。

什么是Node.nodes_except_leafs更好的解决方案,它返回所有非叶子或派生叶子对象(可能来自Node的子类)? THX。

1 个答案:

答案 0 :(得分:3)

下面怎么样:

class Node (db.Model):
    ...
    # original
    nodes_except_leafs = property (lambda self: self.nodes.filter(Node.type != 'leaf'))

    # use outer join (to class) to filter out the Leaf(++)
    nodes_except_leafs = property (lambda self: self.nodes.outerjoin(Leaf, Node.id == Leaf.leaf_id).filter(Leaf.id == None))
相关问题