Django ORM如何舍入平均结果

Ami*_*Ami 11 django orm model average rounding

我有一个模型,我使用Django ORM从表中提取平均值.我想要舍入Avg值,我该怎么做?

请参阅下文我从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')
Run Code Online (Sandbox Code Playgroud)

mrt*_*rts 32

使用Func()表达式.

以下是使用Django Aggregation主题指南中的Book模型在SQLite中舍入到两个小数位的示例:

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

Book.objects.all().aggregate(Round(Avg('price')))
Run Code Online (Sandbox Code Playgroud)

这允许参数化圆函数(来自@ RichardZschech的答案):

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

Book.objects.all().aggregate(Round(Avg('price'), 2))
Run Code Online (Sandbox Code Playgroud)

  • 根据注释或聚合的复杂性,您可能需要分配别名。例如 `Book.objects.all().aggregate(rounded_avg_price=Round(Avg('price')))` (2认同)

Ric*_*ech 9

改进@mrts答案.

这允许参数化圆函数:

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

Book.objects.all().aggregate(Round(Avg('price'), 2))
Run Code Online (Sandbox Code Playgroud)


mso*_*ona 8

基于以前的答案,我来到这个解决方案,使其适用于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
Run Code Online (Sandbox Code Playgroud)


M.V*_*oid 6

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

  • 此功能自 Django >= 2.2 起可用。在 3.3 的开发版本中,他们添加了精度参数。 (3认同)

Bry*_*tte 5

我需要同时支持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))
Run Code Online (Sandbox Code Playgroud)

我更喜欢更干净的东西,比如

if SQLITE:
    arg_joiner=", "
elif PGSQL:
    arg_joiner = '::numeric, '
else raise NotImplemented()
Run Code Online (Sandbox Code Playgroud)

但没找到怎么样,欢迎改进!