7

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

4

3 に答える 3

10

現在では、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
于 2017-03-30T18:44:07.090 に答える
4

単なる概念的なアイデア(メモリから書き込まれる)。

問題は、がorder_byノードモデルを参照していることです。

ただし、

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

これにより、ORMは次のように強制されます。

  1. 'weight'フィールドを追加します。これは通常は省略されます。
  2. 結果を並べ替えます。

クエリの数は、機能した場合と同じである必要がありますprefetch_query。1つはノードを取得し、2つ目は関連ノードを取得します。

残念ながら、を使用する必要があるため、これはあまり「クリーンな」ソリューションではありません_meta

于 2013-02-16T16:16:45.713 に答える
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')
于 2013-02-16T01:45:14.143 に答える