如何使用count多次过滤ManyToMany同一对象

时间:2020-05-12 04:11:18

标签: django django-orm

假设我们的Django模型定义如下:

class Tags(models.Model):
  name = models.CharField(max_length=100, verbose_name = 'Tag name')
  customers = models.ManyToManyField(Customers, related_name='tags', verbose_name = 'Refs to Customer')

class Customers(models.Model):
  name = models.CharField(max_length=100, verbose_name='Display Name')

我想过滤包含所有标签的客户,排除所有标签。

include_all_tags = [1,2]
exclude_all_tags = [3, 4, 5]

但以下查询不起作用:

query = Customers.objects.all()

query = query.filter(tags__id__in=include_all_tags).annotate(c=Count('tags', distinct=True)).filter(c=len(include_all_tags))

query = query.exclude(tags__id__in=exclude_all_tags).annotate(c=Count('tags', distinct=True)).filter(c=len(exclude_all_tags))

SQL输出在这里,但是 ( COUNT ( "core_customertag"."tag_id" ) = 2 AND COUNT ( "core_customertag"."tag_id" ) = 3 ) 是同一别名表的计数!

SELECT
    "core_customers"."id",
    "core_customers"."name",
    COUNT ( "core_customertag"."tag_id" ) AS "c" 
FROM
    "core_customers"
    INNER JOIN "core_customertag" ON ( "core_customers"."id" = "core_customertag"."customer_id" ) 
WHERE
    ( "core_customertag"."tag_id" IN ( 1, 2 ) 
        AND NOT ( "core_customers"."id" IN ( SELECT U1."customer_id" FROM "core_customertag" U1 WHERE U1."tag_id" IN ( 3, 4, 5 ) ) ) 
    ) 
GROUP BY
    "core_customers"."id" 
HAVING
    ( COUNT ( "core_customertag"."tag_id" ) = 2 AND COUNT ( "core_customertag"."tag_id" ) = 3 ) 

预期:

SELECT
    "core_customers"."id",
    "core_customers"."name",
    COUNT ( T1."tag_id" ) AS "c1" 
    COUNT ( T2."tag_id" ) AS "c2" 
FROM
    "core_customers"
    INNER JOIN "core_customertag" T1 ON ( "core_customers"."id" = "core_customertag"."customer_id" ) 
    INNER JOIN "core_customertag" T2 ON ( "core_customers"."id" = "core_customertag"."customer_id" ) 
WHERE
    ( 
      T1."tag_id" IN ( 1, 2 ) 
        AND NOT ( T2."tag_id" IN ( 3, 4, 5 ) ) ) 
    ) 
GROUP BY
    "core_customers"."id" 
HAVING
    ( COUNT ( T1."tag_id" ) = 2 AND COUNT ( T2."tag_id" ) = 3 ) 

0 个答案:

没有答案