Django 通过 ManyToMany 实例对查询进行排序

Django order a query by instance of ManyToMany

我有一个模型 A,其外键指向 B:

class A(models.Model):
    b = models.ForeignKey(B, on_delete=models.CASCADE)

一个多对多关系,带有一个额外的字段,对任何 B 和 C 关系进行加权:

class B2C(models.Model):
    b = models.ForeignKey(B, on_delete=models.CASCADE)
    c = models.ForeignKey(C, on_delete=models.CASCADE)
    weight = models.IntegerField(default=0)

我需要使用 B2C 的权重为给定的 C 实例订购 A 模型 (A.objects.filter(...))。

我只能做一个 A 实例:

# Example of C instance
c = C.objects.get(pk=1)

# Single instance of A
a = A.objects.get(pk=1)

# Getting the weight for this instance
# A => B => B2C WHERE metier=metier
weight = a.b.b2c_set.get(c=c)

但我不知道如何在查询集上应用它(比如在 annotate 中使用它)。

在我的研究过程中,我发现了论文 F()ExpressionWrapperSubQueryannotate,但我不知道如何使用它们来解决我的问题.

感谢阅读:)

正如您已经注意到的,您需要使用 Subquery [Django docs] to annotate the weight. You can use OuterRef to refer to the outer queries b while filtering and also use Coalesce [Django docs] 以防万一以提供默认值:

from django.db.models import OuterRef, Subquery
from django.db.models.functions import Coalesce


weight_subquery = B2C.objects.filter(b=OuterRef('b'), c=given_c_instance)

queryset = A.objects.annotate(
    weight=Coalesce(Subquery(weight_subquery.values('weight')[:1]), 0)
).order_by('weight')