Reputation: 888
Im trying to get all customer list form Cust
models that not having a record in 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)
im trying this but doestn work,
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)
The query above returning:
<QuerySet [<Stat: Ruth>]>
<QuerySet [<Cust: Jhonny>, <Cust: Rony>, <Cust: Sinta>, <Cust: Ruth>]>
As you can see, i need the result [<Stat: Ruth>]
excluded from the data queryset/list.
but what i expected is:
<QuerySet [<Stat: Ruth>]>
<QuerySet [<Cust: Jhonny>, <Cust: Rony>, <Cust: Sinta>>
Upvotes: 1
Views: 401
Reputation: 3248
According to django doc 1 about __in
, it states:
In a given iterable; often a list, tuple, or queryset. It’s not a common use case, but strings (being iterables) are accepted.
There are several ways to solve this problem.
replace
inner_qs = Stat.objects.filter(date__icontains=month)
data = Cust.objects.exclude(id__in=inner_qs)
1. with
inner_qs = Stat.objects.filter(date__icontains=month)
data = Cust.objects.exclude(id__in=[o.cust_id for o in inner_qs])
2. Another way is to replace with
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)
Here, you first generate an exclude id_list then use it to exclude.
3. a revised way of #2 with 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)
Upvotes: 2