Django исключение одного объекта приводит к исключению других объектов
Это самая странная ошибка, с которой я столкнулся с тех пор, как начал использовать Django. У меня есть кверисет с поврежденными данными, которые нужно исключить, при печати длины кверисета он печатает 97, а при печати кверисета с поврежденными данными - 2, поэтому результат должен быть 95, но я получаю только 70!
вот мой код
qs = model.objects.filter(
query,
**sku_filter
).values(
'sku',
'sku__asin',
'sku__title',
).order_by(
'-report_date',
'sku',
).annotate(
in_inbound=Coalesce(
LedgerQuery.in_inbound_subquery,
Value(0)
)
).annotate(
fnsku=F('fnsku'),
action=F('sku__reconciliation_activity__action'),
case_number=F('sku__reconciliation_activity__case_number'),
is_being_manually_reconciled=F('sku__reconciliation_activity__is_being_manually_reconciled'),
missing_subquery_count = Count(missing_subquery_count),
missing=Subquery(
queryset=missing_subquery
),
available=Sum(
'ending_warehouse_balance',
filter=Q(disposition='SELLABLE')
),
total_units=Sum(
F('ending_warehouse_balance') + # Available + Unsellable units in all the countries warehouses
Abs('in_transit_between_warehouses') + # Reserved Component 1
Abs('customer_shipments') # Reserved Component 2
) + F('missing') + F('in_inbound'),
# it's important to put out the missing from the Sum, otherwise
# the result will be missing * grouped by rows
main_image_link=Subquery(
queryset=main_image_link_subquery
)
)
##prints 97
print(qs.count())
##prints 70
print("c1", qs.filter(
~Q(
action=ReconciliationActivity.ActionChoices.NO_ACTION, missing__gte=1
)
).count()
)
##prints 2
print(
qs.filter(
action=ReconciliationActivity.ActionChoices.NO_ACTION, missing__gte=1
).count()
)
Я пытался преобразовать его в sql, чтобы было легче отлаживать, но он состоял из более чем 45k слов, и в итоге я не смог найти в нем ничего плохого
Проблема связана со вторым запросом, в котором вы получаете число 70. Отрицание в наборе запросов с несколькими параметрами работает не так, как вы думаете.
Чтобы это было легче понять, позвольте мне кратко объяснить De Morgan's Law
, что здесь действует.
not (A and B) = not (A) or not (B)
В вашем втором запросе подсчет, который вы получаете, включает все объекты, которые либо не имеют ReconciliationActivity.ActionChoices.NO_ACTION
, либо их missing__get
не равен 1. Если в любом случае true
, то объект вносит свой вклад в значение count.
Правильный запрос, который вы должны написать, следующий:
##prints 95
print("c1", qs.filter(
~Q(
action=ReconciliationActivity.ActionChoices.NO_ACTION
) &
~Q(
missing__gte=1
)
)
).count()
)
И P.S. это не баг. Так условия работают везде.