在Django ManyToMany Through上有效查询额外字段

时间:2011-11-04 04:04:30

标签: python django django-models django-orm

让我们假设模型看起来像这样:

class GraphNode(models.Model):
    name = models.CharField(...)
    edges = models.ManyToManyField('self', through=Edge, 
                                   symmetrical=False)

class Edge(models.Model): 
    source = models.ForeignKey(GraphNode, ...)
    destination = models.ForeignKey(GraphNode, ...)
    edge_type = models.CharField(...)

我想回答如下问题:

从node_n的节点开始,通过边缘类型“foobar”连接的所有节点是什么

我希望可以这样说:

results = GraphNode.objects.filter(source_set==node_n, 
                                   edges__edge_type='foobar')

但是该语法不起作用(边缘跳过直通表,因此没有'edge_type'字段)。也没有:

results = GraphNode.objects.filter(edge__source=node_n, 
                                   edge__edge_type='foobar')

除非我删除ManyToMany字段声明! ,此时上面的查询语法有效。

这是一个错误吗?有没有一个好/更好/最好的方法来查询ManyToMany通过表中的“额外字段”而不使用select_related?

1 个答案:

答案 0 :(得分:0)

您的错误#1正在尝试将Edge用作自身的ManyToMany连接表。如果使用via参数,则必须是第3个表。关系代数不可能通过两个表之一来做m2m。

其次,你不需要这么多。对于多对多,您无法对边缘中的多个节点设置限制。

另一个错误是您使用GraphNode...(source_set=可以边缘过滤,但是将其与节点进行比较。

只需删除多对多字段。

class Edge(models.Model): 
    source = models.ForeignKey(GraphNode, related_name='outcoming')
    destination = models.ForeignKey(GraphNode, related_name='incoming')
    edge_type = models.CharField(...)

 GraphNode.objects.filter(
     Q(outcoming__target=node_n) |  # nodes that have edges that have node_n as target
     Q(incoming__source=node_n)    # the opposite
 )