【问题标题】:Django Sum float valuesDjango Sum 浮点值
【发布时间】:2021-01-28 09:42:29
【问题描述】:

我在 Django 中有一个模型,它有三个字段。浮点数和两个 CharFields。我需要将其他两个浮点字段相加。

models.py

class Hours(model.Model):
    hours_worked = models.FloatField()
    order_number = models.CharField()
    oper = models.CharField()

我需要做的是遍历数据库中的所有数据,并对相同的 order_number+oper 求和 hours_worked。 所以假设我有 db 4 记录:

|hours_worked|order_number|oper|
|------------|------------|----|
|           4|         252|  10|
|           8|         320|  20|
|           8|         252|  10|
|           6|         252|  20|

我需要像这样返回三个对象的查询集:

|hours_worked|order_number|oper|
|------------|------------|----|
|          12|         252|  10|
|           8|         320|  20|
|           6|         252|  20|

有什么简单的方法吗?

【问题讨论】:

    标签: python django model


    【解决方案1】:

    这里有两种可能的解决方案(当然还有其他的)

    使用django-group-by

    from django_group_by import GroupByMixin
    
    class GroupedHoursQuerySet(QuerySet, GroupByMixin):
        def select_related(self, *fields):
            try:
                return super().select_related(*fields)  # once grouping was applied, select_related will fail
            except TypeError:
                return self
    
    class GroupedHours(Hours):
        objects = GroupedHoursQuerySet.as_manager()
        class Meta:
            proxy = True
    

    并查询数据:

    from django.contrib.postgres.aggregates import ArrayAgg, StringAgg
    from django.db.models import Sum
    
    qs = GroupedHours.objects.group_by('order_number', 'oper').annotate(
        hours_worked=Sum('hours_worked'),
        pks=ArrayAgg('id'),
        pk=StringAgg(Cast('id', output_field=TextField()), '-'),
    ).distinct()
    

    返回的查询集中的对象具有与原始模型相同的属性,但hours_worked 包含总和:

    for gh in qs:
        print(f'Operator {gh.oper} worked {gh.hours_worked} on order {gh.order_number}')
    

    Django 的values()

    如果您不需要 Django 模型对象只是实际数字,您当然可以在没有 django-group-by 模块的情况下使用聚合和注释。

    以下方法也可能有效(未经测试),请参阅the documentation 了解更多详情:

    from django.db.models import Sum
    
    qs = Hours.objects.values('order_number', 'oper').annotate(
        worktime=Sum('hours_worked')
    

    可能需要添加.distinct()

    这会返回一个字典:

    for gh in qs:
        print(f'Operator {gh['oper']} worked {gh['hours_worked']} on order {gh['order_number']}')
    

    【讨论】:

    • valuesannotate 对于一个简单的 group by 来说不够吗?为什么要一个单独的包来做到这一点?
    • @AbdulAzizBarkat - 取决于用例。我喜欢使用 django-group-by,因为它返回一个带有 django 模型对象的查询集,这样我就可以重用已经存在于常规模型对象的大部分代码。您的评论非常有效,特别是对于这个只有 3 个字段的模型 - 所以我添加了一个带有值解决方案的代码 sn-p。
    • 这很有用,顺便注意到在 sn-p 中 oper 附近缺少引号。 :)
    • 谢谢,修复了引用并添加了有关如何访问字段/属性的示例,以说明 .values() 和其他解决方案之间的区别。
    • @Risadinha 我在 models.py 中有更多模型,我收到了'Person' object has no attribute 'group_by'。有什么想法吗?
    猜你喜欢
    • 2020-08-18
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2018-12-18
    • 2023-04-07
    • 2019-12-15
    相关资源
    最近更新 更多