首页 > 解决方案 > 在过滤的查询集中获取重复的记录

问题描述

| &我有一个像这样的过滤器有点复杂的组合。

objs = objs.annotate(num_line=Count("lns")).\
    filter(Q(lns__id__in=lnIds) | (Q(sts__id__in=oIds) 
        & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))))

它看起来像工作,但结果有时会被重复(具有相同的 id)。

   id
    1
    2
    3
    3
    4
    5

我认为过滤器可以保证返回唯一的ID,我错了吗?

或者是否可以省略重复的行?

class Obj(models.Model):
    created_at = models.DateTimeField(null=True)
    lns = models.ManyToManyField(Ln)
    sts = models.ManyToManyField(St)
    is = models.ManyToManyField(Is)
    pub_date = models.DateTimeField('date published')

标签: pythondjangodjango-queryset

解决方案


不,如果您在一对多或多对多关系中进行过滤,它将与相关表创建一个 JOIN,如果多个对象匹配,那么这将导致多次产生相同的值。

您可以使用.distinct(..)( Django-doc ) 过滤重复的行。

objs = objs.filter(
    Q(lns__id__in=lnIds) |
    (Q(sts__id__in=oIds) & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))
).distinct()

更有问题的是,如果您添加注释,那么这可能导致计数也会计算重复项。您可以将distinct=True[Django-doc]添加到Count(..)表达式中以防止:

objs = objs.annotate(
    num_line=Count('lns', distinct=True)
).filter(
    Q(lns__id__in=lnIds) |
    (Q(sts__id__in=oIds) & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))
).distinct()

推荐阅读