Что происходит, так это то, что запрос exclude () все портит. По сути, он исключает любой Order_type, у которого есть хотя бы один Order без статуса, что почти наверняка не то, чего вы хотите.
Самое простое решение в вашем случае - использовать order__status__gt=''
в аргументах filter (). Однако вам также необходимо добавить distinct()
в конец вашего запроса, потому что в противном случае вы получите QuerySet с несколькими экземплярами одного и того же Order_type, если у него более одного Order, соответствующего запросу. Это должно работать:
qs = Order_type.objects.filter(
order__order_date__lte=datetime.date.today(),
order__processed_time__isnull=True,
order__status__gt='').distinct()
В дополнение к заметке, в вопросе qs, который вы дали в конце вопроса, вам не нужно говорить order__id__in=[o.id for o in orders_qs]
, вы можете просто использовать order__in=orders_qs
(вам все еще нужен distinct()
). Так что это также будет работать:
qs = Order_type.objects.filter(order__in=Order.objects.filter(
order_date__lte=datetime.date.today(),
processed_time__isnull=True).exclude(status='')).distinct()
Приложение (изменить):
Вот фактический SQL, который Django выдает для указанных наборов запросов:
SELECT DISTINCT "testapp_order_type"."id", "testapp_order_type"."description"
FROM "testapp_order_type"
LEFT OUTER JOIN "testapp_order"
ON ("testapp_order_type"."id" = "testapp_order"."type_id")
WHERE ("testapp_order"."order_date" <= E'2010-07-18'
AND "testapp_order"."processed_time" IS NULL
AND "testapp_order"."status" > E'' );
SELECT DISTINCT "testapp_order_type"."id", "testapp_order_type"."description"
FROM "testapp_order_type"
INNER JOIN "testapp_order"
ON ("testapp_order_type"."id" = "testapp_order"."type_id")
WHERE "testapp_order"."id" IN
(SELECT U0."id" FROM "testapp_order" U0
WHERE (U0."order_date" <= E'2010-07-18'
AND U0."processed_time" IS NULL
AND NOT (U0."status" = E'' )));
EXPLAIN показывает, что второй запрос немного дороже (стоимость 28,99 против 28,64 с очень маленьким набором данных).