Аннотированное поле Django Sum
Я пытаюсь суммировать аннотированное поле в Python
Первый,
class InvoiceItems(models):
units = FloatField(...)
price = FloatField(...)
sku = CharField(...)
Итак, я хочу annotate перечислить units * price затем Sum() их все для заданного sku но
qs = InvoiceItems.annotate(
amount=Sum(F('units')*F('price'), output_field=models.FloatField())
)
не работает.
Мой фактический код:
def customer_purchase_detail(**kwargs):
from_date = kwargs.get('from_date', False)
to_date = kwargs.get('to_date', False)
channel = kwargs.get('channel', False)
customer = kwargs.get('customer', False)
sku = kwargs.get('sku', False)
query_set = Invoice.objects.filter(
record_type=3,
)
if from_date:
query_set = query_set.filter(date__gte=datetime.datetime.strptime(from_date, '%Y-%m-%d'))
if to_date:
query_set = query_set.filter(date__lte=datetime.datetime.strptime(to_date, '%Y-%m-%d'))
if channel:
query_set = query_set.filter(order__customer__category=channel)
if customer:
query_set = query_set.filter(order__customer__code=customer)
if sku:
query_set = query_set.filter(order__orderitem__product__sku=sku)
query_set = query_set.annotate(
amount=Sum(
((F('order__orderitem__order_quantity') - F('order__orderitem__cancel_quantity')) * F(
'order__orderitem__unit_price')) - F('order__orderitem__discount_amount'),
output_field=models.FloatField()
),
quantity=Sum(
(F('order__orderitem__order_quantity') - F('order__orderitem__cancel_quantity') -
F('order__orderitem__remove_quantity')) *
F('order__orderitem__pieces_per_unit'),
output_field=models.IntegerField()
)
)
query_set = query_set.values(
'order__orderitem__product__sku',
'order__orderitem__product__description',
'order__orderitem__product__description_en',
'amount',
'quantity'
).order_by('-amount').all()
total = reduce(lambda acc, x: acc + x['amount'], query_set, 0)
result = [
{
'sku': q['order__orderitem__product__sku'],
'name': q['order__orderitem__product__description'],
'name_en': q['order__orderitem__product__description_en'],
'amount': q['amount'],
'quantity': q['quantity'],
'ppu': round((q['amount'] / q['quantity']) if q['quantity'] > 0 else 0),
'pct': round(q['amount'] / total, 3)
}
for q in query_set
]
# Made this a list for JsonResponse() that this query returns to
return result
Если моя таблица
sku | unit | price
AA | 2 | 1.00
AA | 3 | 2.00
AA | 5 | 2.00
BB | 4 | 1.00
Я хочу получить результат
sku | amount
AA | 8
BB | 4
но набор результатов, который отправляет Django, таков
sku | amount
AA | 8
AA | 10
BB | 4
Так что суммирование и группировка одних множеств, не других. P.S. Я заметил, что в простом примере это работает так, как у меня работает с другим запросом. А с этим почему-то не работает. Буду признателен за любой совет! Спасибо!
Вы должны группировать по sku, так:
qs = InvoiceItems.values('sku').annotate(
amount=Sum(F('units')*F('price'), output_field=models.FloatField())
).order_by('sku')
Это создаст QuerySet словарей, так:
<QuerySet [
{'sku': 'AA', 'amount': 8},
{'sku': 'BB', 'amount': 4}
]>
При этом, возможно, будет лучше сделать модель Product, и таким образом использовать ForeignKey к ней Product вместо sku.
Я не знаю почему это работает, но я переместил свои фильтры
if from_date:
query_set = query_set.filter(date__gte=datetime.datetime.strptime(from_date, '%Y-%m-%d'))
if to_date:
query_set = query_set.filter(date__lte=datetime.datetime.strptime(to_date, '%Y-%m-%d'))
if channel:
query_set = query_set.filter(order__customer__category=channel)
if customer:
query_set = query_set.filter(order__customer__code=customer)
if sku:
query_set = query_set.filter(order__orderitem__product__sku=sku)
после annotate и теперь все работает.