【问题标题】:Django - Annotating Weighted AVG by GroupDjango - 按组注释加权 AVG
【发布时间】:2016-12-10 01:08:25
【问题描述】:

我有以下对销售记录进行操作的模型管理器:

def by_variety_and_date(self, start_date, end_date):
    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "variety"
    ).annotate(
        qty_applied=Sum('qty_applied'),
        margin=Avg('margin')
    )

我真正希望margin=Avg('margin') 返回基于qty_applied加权平均值。有没有办法用 Django 的注释/聚合查询来做到这一点?我一直在尝试将 .aggregate() 字符串化到最后,但我仍然想要这个查询集所描述的每个 variety 的平均值。

本例中的模型如下所示:

class Sale(models.Model):
    margin = models.DecimalField(null=True, blank=True, decimal_places=2, max_digits=12)
    qty_applied = models.IntegerField(null=True, blank=True)
    variety = models.ForeignKey(Variety, null=True)
    totals = Totals()

编辑

这就是我最终得到的结果。这有点奇怪,但它确实可以解决问题。

def by_variety_and_date(self, start_date, end_date):
    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "variety"
    ).annotate(
        qty_applied=Sum('qty_applied'),
        profit=Sum('profit'),
        cogs=Sum('cogs'),
        sales=Sum('value'),
        margin=Sum(
            (F('qty_applied')*F('margin')), output_field=FloatField()
        ) / Sum(
            'qty_applied', output_field=FloatField())
    )

我使用F对象作为@WTower建议将每个对象的margin乘以它的qty_applied,然后将整个东西包裹在Sum中并除以qty_appliedSum组中的所有对象。奇迹般有效!

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    您可以使用F() expression

    >>> from django.db.models import F, FloatField, Sum
    >>> MyModel.objects.all().aggregate(
    ...    w_avg=Sum((F('a')*F('b'))/F('b'), output_field=FloatField()))
    

    更多关于聚合here

    或者,您可以使用自定义 SQL(推荐)或管理器中的自定义方法。

    【讨论】:

    • 不需要自定义 SQL :)。这是一个自定义管理器方法,顺便说一句。
    猜你喜欢
    • 2016-09-20
    • 2018-03-21
    • 1970-01-01
    • 2011-04-02
    • 2017-04-07
    • 1970-01-01
    • 2014-03-17
    • 2020-01-26
    • 1970-01-01
    相关资源
    最近更新 更多