如何在Django中预取相关对象并按中间表中的字段对它们进行排序?
以下是我正在使用的模型:
class Node(models.Model):
name = models.CharField(max_length=255)
edges = models.ManyToManyField('self', through='Edge', symmetrical=False)
class Edge(models.Model):
from_node = models.ForeignKey(Node, related_name='from_node')
to_node = models.ForeignKey(Node, related_name='to_node')
weight = models.FloatField(default=0)
给定一个节点,我想预取所有相关的节点,按权重排序。
当我使用此查询时:
n = Node.objects.prefetch_related('to_node').order_by('edge__weight').get(name='x')
order_by无效。
修改
到目前为止我的最佳答案
n = Node.objects.get(name='x')
edges = Edge.objects.filter(from_node=n).prefetch_related('to_node').order_by('weight')
然后迭代n.edges
edges.to_node
(我更喜欢)
答案 0 :(得分:7)
如今,您还可以使用Prefetch类来实现此目的:
https://docs.djangoproject.com/en/1.10/ref/models/querysets/#django.db.models.Prefetch
或者,如果您希望始终将此作为默认值,则可以查看中间表上的元排序,例如:
class SomeThroughModel(models.Model):
order = models.IntegerField("Order", default=0, blank=False, null=False)
...
class Meta:
ordering = ['order'] # order is the field holding the order
答案 1 :(得分:4)
只是一个概念性的想法(从记忆中写出来)。
问题是,order_by
是指节点模型。
然而,有一种方法
Node.objects.get(name='x').edges.extra(select={'weight':'%s.weight' % Edge._meta.db_table}).order_by('weight')
这将迫使ORM:
查询数量应与prefetch_query
工作时相同,一个用于获取节点,第二个用于获取相关节点。
不幸的是,这不是一个非常“干净”的解决方案,因为我们需要使用_meta
。
答案 2 :(得分:0)
虽然不是那么干净..
//Untested Code
Node n = Node.objects.get(name="x")
//This would return To Node IDs' ordered by weight
n.edges.filter(from_node = n).values_list('to_node', flat=True).order_by('weight')