【问题标题】:SQLAlchemy and filtering polymorphic queriesSQLAlchemy 和过滤多态查询
【发布时间】:2012-11-25 23:34:52
【问题描述】:

我有 Node 和 Leaf (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.type == 'nodeex' 的NodeEx 对象。

对于返回所有非叶或派生的叶对象(可能从Node 的子类派生)的Node.nodes_except_leafs 有什么更好的解决方案?谢谢。

【问题讨论】:

    标签: inheritance sqlalchemy polymorphic-associations flask-sqlalchemy


    【解决方案1】:

    下面怎么样:

    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))
    

    【讨论】:

    • 感谢答案:它原则上有效,但实际上不是我想要的,因为您的建议未能省略已使用 Leaf 的子类实例化的叶子,例如leafex = LeafEx (..) 其中class LeafEx (Leaf) 和LeafEx.type == 'leafex'。 (经过测试)
    • 用解决问题的版本更新了答案
    猜你喜欢
    • 1970-01-01
    • 2019-03-10
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多