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
.