Django 如何用计数注释 manytomany 字段

Django how to annotate manytomany field with count

考虑以下几点:

class ModelA(models.Model):
    pass

class ModelB(models.Model):
    model_as = models.ManyToManyField(ModelA, db_index=True, related_name="model_bs", blank=True)


model_bs = model_a_object.model_bs.all()
for model_b in model_bs:
    print(model_b.model_as.count())
3
2

到目前为止一切顺利。但我想根据 model_as 的计数创建 model_bs 的有序列表。我的理解是,这应该可以解决问题:

model_bs = model_a_object.model_bs.all().annotate(count=Count("model_as")).order_by('count')

出于某种原因,这不起作用。当我打印检查时,注释的 count 是错误的!!

for model_b in model_bs:
    print(model_b.model_as.count(), model_b.count)
3 1
2 1

我做错了什么?这是 print(model_bs.query) 的 sql 输出:

SELECT "mobile_modelb"."id",
       "mobile_modelb"."modelb",
       COUNT(DISTINCT "mobile_modelb_model_as"."modela_id") AS "count"
FROM "mobile_modelb"
INNER JOIN "mobile_modelb_model_as" ON ("mobile_modelb"."id" = "mobile_modelb_model_as"."modelb_id")
WHERE "mobile_modelb_model_as"."modela_id" = 7
GROUP BY "mobile_modelb"."id"
ORDER BY "count" ASC

尝试将 distinct=True 添加到计数中。

model_bs = model_a_object.model_bs.all().annotate(
    count=Count("model_as", distinct=True)
).order_by('count')

编辑:

问题是因为您正在使用 model_a_object.model_bs.all(),您生成了这个 WHERE 子句:

WHERE "mobile_modelb_model_as"."modela_id" = 7

解决方案可能是:

ModelB.objects.annotate(
    count=Count("model_as")
).filter(model_as=model_object_a)

如果这不起作用,请尝试在 filter() 之前使用 values() 以正确定义 GROUP BY。

ModelB.objects.annotate(
    count=Count("model_as")
).values('id', 'count').filter(model_as=model_object_a)