让我们假设模型看起来像这样:
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?
答案 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
)