Аннотированное поле 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 и теперь все работает.

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