Django Sum 带注释的字段

发布于 2025-01-13 22:26:11 字数 3089 浏览 2 评论 0原文

我试图首先对 Python 中的带注释字段进行求和

class InvoiceItems(models):
  units = FloatField(...)
  price = FloatField(...)
  sku = CharField(...)

所以我想对 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 | 18
BB | 4

,但 Django 发送的结果集是,

sku | amount
AA | 8
AA | 10
BB | 4

所以对一些集合而不是其他集合进行求和和分组。 PS我注意到在这个简单的例子中,它的工作原理就像我让它与另一个查询一起工作一样。不知何故,这与此无关。 任何建议将不胜感激!谢谢!

I'm trying to sum an annotated field in Python

First,

class InvoiceItems(models):
  units = FloatField(...)
  price = FloatField(...)
  sku = CharField(...)

So I want to annotate the units * price then Sum() them all up for a given sku but

qs = InvoiceItems.annotate(
  amount=Sum(F('units')*F('price'), output_field=models.FloatField())
)

isn't working.

My actual code:


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

If my table is

sku | unit | price
AA | 2 | 1.00
AA | 3 | 2.00
AA | 5 | 2.00
BB | 4 | 1.00

I want the result

sku | amount
AA | 18
BB | 4

but the result set Django is sending out is

sku | amount
AA | 8
AA | 10
BB | 4

So summing and grouping some sets, not others.
P.S. I noticed that in the simple example, it works as I have it working with another query. Somehow it doesn't with this one.
Any advice would be appreciated! Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云之铃。 2025-01-20 22:26:11

您应该按 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 模型,因此对该 Product 使用 ForeignKey 而不是 sku

You should group by the sku, so:

qs = InvoiceItems.values('sku').annotate(
  amount=Sum(F('units')*F('price'), output_field=models.FloatField())
).order_by('sku')

This will make a QuerySet of dictionaries, so:

<QuerySet [
    {'sku': 'AA', 'amount': 8},
    {'sku': 'BB', 'amount': 4}
]>

That being said, it might be better to make a Product model, and thus use a ForeignKey to that Product instead of a sku.

爱人如己 2025-01-20 22:26:11

我不知道为什么这有效,但我

    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)

注释之后移动了过滤器,现在一切正常了。

I don't know why this works, but I moved my filters

    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)

after the annotate and all works now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文