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. это не баг. Так условия работают везде.

Вернуться на верх