#django #django-queryset
#django #django-набор запросов
Вопрос:
Я пытаюсь получить все модели формы списка клиентов 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>]>
Как вы можете видеть, мне нужен результат [<Stat: Ruth>]
, исключенный из набора / списка запросов данных.
но я ожидал, что:
<QuerySet [<Stat: Ruth>]>
<QuerySet [<Cust: Jhonny>, <Cust: Rony>, <Cust: Sinta>>
Ответ №1:
Согласно документу django doc 1 about __in
, в нем говорится:
В заданном итерируемом; часто список, кортеж или набор запросов. Это не обычный вариант использования, но строки (являющиеся итеративными) принимаются.
Есть несколько способов решить эту проблему.
заменить
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)
Здесь вы сначала создаете список идентификаторов исключения, а затем используете его для исключения.
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)
Комментарии:
1. Спасибо! это работает! мне нужно только изменить
id
cust_id
в данном решении, чтобы оно заработало@2. упс!!! Я пропустил эту часть. Я отредактировал свой ответ и добавил метод distinct().