цепочечный фильтр и исключает на django модели с полевыми поисками тот промежуток отношения

У меня есть следующие модели:

class Order_type(models.Model):
    description = models.CharField()

class Order(models.Model):
    type= models.ForeignKey(Order_type)
    order_date = models.DateField(default=datetime.date.today)
    status = models.CharField()
    processed_time= models.TimeField()

Я хочу список типов порядка, которые имеют заказы, которые встречают это критерии: (order_date <= сегодня И processed_time пусто И status не пробел),

Я попробовал:

qs = Order_type.objects.filter(order__order_date__lte=datetime.date.today(),\
     order__processed_time__isnull=True).exclude(order__status='')

Это работает на исходный список заказов:

orders_qs = Order.objects.filter(order_date__lte=datetime.date.today(), processed_time__isnull=True)
orders_qs = orders_qs.exclude(status='')

Но qs не право queryset. Я думаю его на самом деле возврат более суженного фильтра (так как никакие записи не присутствуют), но я не уверен что. Согласно этому (django ссылка), потому что я ссылаюсь на связанную модель, я думаю исключить работы над исходным queryset (не тот от фильтра), но я не добираюсь точно как.

Хорошо, я просто думал об этом, которое я думаю работы, но чувствует себя неаккуратным (Существует ли лучший путь?):

qs = Order_type.objects.filter(order__id__in=[o.id for o in orders_qs])

5
задан cezar 20 February 2018 в 10:09
поделиться

1 ответ

Происходит то, что запрос exclude() все портит. По сути, он исключает все типы заказов, в которых есть хотя бы один заказ без статуса, что почти наверняка не то, чего вы хотите.

Самое простое решение в вашем случае - использовать 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 при очень маленьком наборе данных).

6
ответ дан 14 December 2019 в 13:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: