2013-02-15 52 views
7

如何在Django中預取相關對象並按中間表中的字段排序?Django:根據中間表字段排序的prefetch_related結果

這裏是我的工作模型:

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

您正在將節點表上的order by子句放在邊緣表上。所以,所提到的結果是可以預料的。 – 2013-02-15 23:19:49

+0

確實,但它怎麼能放在邊桌上呢? – 2013-02-15 23:29:26

回答

4

只是一個概念性的想法(從記憶中寫出)。

問題是,order_by引用了Node模型。

然而,有一種方法可以

Node.objects.get(name='x').edges.extra(select={'weight':'%s.weight' % Edge._meta.db_table}).order_by('weight') 

這將迫使ORM到:

  1. 添加 '重量' 領域,這通常會被省略。
  2. 按順序排列結果。

查詢次數應該與prefetch_query工作時相同,一次獲取節點,第二次獲取相關節點。

不幸的是,這不是一個非常'乾淨'的解決方案,因爲我們需要使用_meta

+1

可能不乾淨,但我可以確認它確實有效。謝謝! – 2013-02-16 18:12:54

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

如今,你還可以使用預取類來實現這一目標:

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 
相關問題