我需要查找包含status = completed的所有订单商品的订单。它看起来像这样:
FINISHED_STATUSES = [17,18,19]
if active_tab == 'outstanding':
orders = orders.exclude(items__status__in=FINISHED_STATUSES)
但是,此查询仅向我提供具有已完成状态的任何订单商品的订单。我如何进行查询,以便仅检索具有已完成状态的所有订单商品的订单?
答案 0 :(得分:3)
我认为你需要在这里进行原始查询:
将订单和商品模型设置为订单和商品:
# 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)
答案 1 :(得分:1)
我能够通过一种hackish方式完成这项工作。首先,我添加了一个额外的布尔列is_finished
。然后,查找包含至少一个未完成项目的订单:
orders = orders.filter(items__status__is_finished=False)
这给了我所有未完成的订单。
与此相反的是获得完成的订单:
orders = orders.exclude(items__status__is_finished=False)
答案 2 :(得分:0)
添加布尔字段是个好主意。这样,您就可以在模型中明确定义业务规则。
现在,让我们说你仍然想要在不借助添加字段的情况下这样做。考虑到不同的情况,这可能是一个要求。不幸的是,你不能在Django ORM中真正使用子查询或任意连接。但是,您可以构建Q
个对象,并使用filter()
和annotate()
在having子句中进行隐式连接。
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虽然不那么优雅,但通常会更有效率。