Django group by after annotate не работает

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

class Order(models.Model):
    ...
    org_slug = models.CharField()

class ProductToOrder(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    qty = models.IntegerField()
    cost = models.FloatField()

Мне нужно просуммировать заказы, сгруппированные по org_slug, и у него должна быть сумма заказов, которые имеют только один ProductToOrder и ProductToOrder.qty=1

Я пытаюсь сделать это таким образом

        orders = Order.objects.filter(
            some_filter_here
        ).values('org_slug').annotate(
            order_sum=Subquery(Order.objects.filter(
                org_slug=OuterRef('org_slug')).annotate(
                    product_count=Coalesce(Sum('producttoorder__qty'), 1)
        ).filter(product_count=1).values('org_slug').annotate(
            sum=Sum('producttoorder__cost')
        ).values('sum')[:1]

Но он возвращает набор всех заказов. Например, если у меня 1000 заказов и 2 org_slugs, мне нужно получить 2 объекта в списке запроса, но он возвращает 1000. Эта строка, где я пытаюсь сгруппировать по кверисету в следующем подзапросе, не работает:

.filter(product_count=1).values('org_slug')

Я перепробовал множество различных наборов запросов, чтобы исправить это, но это не дало мне никакого положительного результата. Я вижу только один способ исправить это, мне нужно создать поле qty в модели заказа, но я надеюсь, что есть и другие способы исправить это. Может ли кто-нибудь помочь мне с этим?

Мне кажется, вы слишком усложняете ситуацию. Вы можете работать с:

from django.db.models import Sum

Order.objects.filter(org_slug=my_slug, producttoorder__qty=1).annotate(
    total=Sum('producttoorder__cost')
)

Это позволит получить Order объекты с org_slug=my_slug и просуммировать cost всех связанных ProductToOrder с ними объектов.

Однако здесь есть оговорка: он также будет суммироваться, если есть -множество ProductToOrder с qty=1. Если вы хотите опустить их, мы можем работать с:

from django.db.models import Count, Exists, OuterRef, Sum

Order.objects.filter(
    ~Exists(ProductToOrder.objects.filter(~Q(qty=1), order_id=OuterRef('pk'))),
    org_slug=my_slug,
    producttoorder__qty=1,
).annotate(total=Sum('producttoorder__cost'), num=Count('producttoorder')).filter(
    num=1
)

Таким образом, мы будем рассматривать только Order с одним ProductToOrder, у которого есть qty=1.

Вернуться на верх