Django 2.2 ORM 排除未按预期工作

Django 2.2 ORM Exclude Not Working as expected

我正在尝试从 Cust 模型中获取所有在 Stat (ForeignKey)、Django 2.2 中没有记录的客户列表


class Cust(models.Model):
    name = models.CharField(max_length=50)
    active = models.BooleanField(default=True)


class Stat(models.Model):
    cust = models.ForeignKey(Cust, on_delete=models.PROTECT, null=True)
    date = models.DateField(null=True, blank=True)
    

我正在尝试这个但没有用,

    month = datetime.now()
    month = month.strftime("%Y-%m")
    
    inner_qs = Stat.objects.filter(date__icontains=month)
    data = Cust.objects.exclude(id__in=inner_qs)
    
    print(inner_qs)
    print(data)

上面的查询返回:


<QuerySet [<Stat: Ruth>]>
<QuerySet [<Cust: Jhonny>, <Cust: Rony>, <Cust: Sinta>, <Cust: Ruth>]>

如您所见,我需要从数据 queryset/list 中排除结果 [<Stat: Ruth>]

但我期望的是:

<QuerySet [<Stat: Ruth>]>
<QuerySet [<Cust: Jhonny>, <Cust: Rony>, <Cust: Sinta>>

根据 django 文档 1 关于 __in,它指出:

In a given iterable; often a list, tuple, or queryset. It’s not a common use case, but strings (being iterables) are accepted.

有几种方法可以解决这个问题。

替换

    inner_qs = Stat.objects.filter(date__icontains=month)
    data = Cust.objects.exclude(id__in=inner_qs)

1.

    inner_qs = Stat.objects.filter(date__icontains=month)
    data = Cust.objects.exclude(id__in=[o.cust_id for o in inner_qs])

2.另一种方式是用

代替
    id_list =Stat.objects.filter(date__icontains=month)\
            .values_list('cust_id', flat=True)\ 
            # flat=True will return list rather 
            # than tuple in the ValueListQueryset

    data = Cust.objects.exclude(id__in=id_list)

在这里,你首先生成一个排除id_list然后用它来排除。

3. #2 的修改方式 distinct()

    id_list =Stat.objects.filter(date__icontains=month)\
            .values_list('cust_id', flat=True)\
            .distinct().order_by() 
            # distinct() is used to get unique 'cust_id's
            # distinct() does not work without order_by()

    data = Cust.objects.exclude(id__in=id_list)