2

我有课程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?谢谢。

4

1 回答 1

4

下面怎么样:

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))
于 2012-11-26T11:44:28.363 回答