我需要找到一个包含所有状态 = 已完成的订单项目的订单。它看起来像这样:
FINISHED_STATUSES = [17,18,19]
if active_tab == 'outstanding':
orders = orders.exclude(items__status__in=FINISHED_STATUSES)
但是,此查询仅给我提供任何具有已完成状态的订单项目的订单。我将如何进行查询,以便仅检索具有已完成状态的所有订单项目的那些订单?
我认为您需要在这里进行原始查询:
将您的订单和项目模型设置为订单和项目:
# raw query
sql = """\
select `orders`.* from `%{orders_table}s` as `orders`
join `%{items_table}s` as `items`
on `items`.`%{item_order_fk}s` = `orders`.`%{order_pk}s`
where `items`.`%{status_field}s` in (%{status_list}s)
group by `orders`.`%{orders_pk}s`
having count(*) = %{status_count)s;
""" % {
"orders_table": Orders._meta.db_table,
"items_table": Items._meta.db_table,
"order_pk": Orders._meta.pk.colum,
"item_order_fk":Items._meta.get_field("order").colum,
"status_field": Items._meta.get_field("status").colum,
"status_list": str(FINISHED_STATUSES)[1:-1],
"status_count": len(FINISHED_STATUSES),
}
orders = Orders.objects.raw(sql)
我能够通过一种骇人听闻的方式完成这项工作。首先,我添加了一个额外的布尔列,is_finished
. 然后,要查找至少有一个未完成项目的订单:
orders = orders.filter(items__status__is_finished=False)
这给了我所有未完成的订单。
做相反的事情得到完成的订单:
orders = orders.exclude(items__status__is_finished=False)
添加布尔字段是个好主意。这样,您就可以在模型中清楚地定义业务规则。
现在,假设您仍然想在不借助添加字段的情况下执行此操作。考虑到不同的情况,这很可能是一项要求。不幸的是,您不能真正在 Django ORM 中使用子查询或任意连接。但是,您可以使用and构建Q
对象并在 having 子句中进行隐式连接。filter()
annotate()
from django.db.models.aggregates import Count
from django.db.models import Q
from functools import reduce
from operator import or_
total_items_by_orders = Orders.objects.annotate(
item_count=Count('items'))
finished_items_by_orders = Orders.objects.filter(
items__status__in=FINISHED_STATUSES).annotate(
item_count=Count('items'))
orders = total_items_by_orders.exclude(
reduce(or_, (Q(id=o.id, item_count=o.item_count)
for o in finished_items_by_orders)))
请注意,使用原始 SQL 虽然不太优雅,但通常会更有效。