1

我需要找到一个包含所有状态 = 已完成的订单项目的订单。它看起来像这样:

FINISHED_STATUSES = [17,18,19]
if active_tab == 'outstanding':
    orders = orders.exclude(items__status__in=FINISHED_STATUSES)

但是,此查询仅给我提供任何具有已完成状态的订单项目的订单。我将如何进行查询,以便仅检索具有已完成状态的所有订单项目的那些订单?

4

3 回答 3

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)
于 2013-03-08T01:55:43.240 回答
1

我能够通过一种骇人听闻的方式完成这项工作。首先,我添加了一个额外的布尔列,is_finished. 然后,要查找至少有一个未完成项目的订单:

orders = orders.filter(items__status__is_finished=False)

这给了我所有未完成的订单。

做相反的事情得到完成的订单:

orders = orders.exclude(items__status__is_finished=False)
于 2013-03-08T05:48:17.303 回答
0

添加布尔字段是个好主意。这样,您就可以在模型中清楚地定义业务规则。

现在,假设您仍然想在不借助添加字段的情况下执行此操作。考虑到不同的情况,这很可能是一项要求。不幸的是,您不能真正在 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 虽然不太优雅,但通常会更有效。

于 2013-03-08T14:58:46.223 回答