18

我有一个模型,我在其中使用 Django ORM 从表中提取平均值。我想四舍五入该平均值,我该怎么做?

见下文我从价格模型中提取平均价格,按日期分组,格式为 YYYY-MM,我想自动提取四舍五入到最接近数字的平均值。

rs = Prices.objects.all.extra(select={
    'for_date': 'CONCAT(CONCAT(extract( YEAR from for_date ), "-"),
        LPAD(extract(MONTH from for_date), 2, "00"))'
    }).values('for_date').annotate(price=Avg('price')).order_by('-for_date')
4

5 回答 5

44

使用Func() 表达式

这是一个使用Django Aggregation 主题指南中的 Book 模型在 SQLite 中四舍五入到小数点后两位的示例:

class Round(Func):
    function = 'ROUND'
    template='%(function)s(%(expressions)s, 2)'

Book.objects.all().aggregate(Round(Avg('price')))

这允许对 round 函数进行参数化(来自@RichardZschech 的回答):

class Round(Func):
  function = 'ROUND'
  arity = 2

Book.objects.all().aggregate(Round(Avg('price'), 2))
于 2016-01-05T22:30:03.127 回答
19

基于以前的答案,我来到这个解决方案以使其适用于PostgreSQL

from django.db.models import Func

class Round2(Func):
    function = "ROUND"
    template = "%(function)s(%(expressions)s::numeric, 2)"

# Then use it as ,e.g.:
# queryset.annotate(ag_roi=Round2("roi"))

# qs.aggregate(ag_sold_pct=Round2(Sum("sold_uts") / (1.0 * Sum("total_uts"))) * 100
于 2018-08-27T12:28:46.720 回答
15

改进@mrts 答案。

这允许对轮函数进行参数化:

class Round(Func):
  function = 'ROUND'
  arity = 2

Book.objects.all().aggregate(Round(Avg('price'), 2))
于 2018-05-11T13:21:31.063 回答
4

我需要同时支持PostgreSQLSQLite,但还要保持指定要保留的位数的能力。

建立在以前的答案:

class Round(Func):
    function = 'ROUND'
    arity = 2
    # Only works as the arity is 2
    arg_joiner = '::numeric, '

    def as_sqlite(self, compiler, connection, **extra_context):
        return super().as_sqlite(compiler, connection, arg_joiner=", ", **extra_context)

# Then one can use it as:
# queryset.annotate(avg_val=Round(AVG("val"), 6))

我更喜欢更干净的东西

if SQLITE:
    arg_joiner=", "
elif PGSQL:
    arg_joiner = '::numeric, '
else raise NotImplemented()

但是没有找到方法,请随时改进!

于 2019-04-29T14:58:31.067 回答
3

Django 有这个Round功能。有关更多详细信息,请参阅文档

于 2020-08-26T13:08:13.647 回答