Django注释output_field = DecimalField忽略max_digits和decimal_places

时间:2017-02-15 11:56:38

标签: mysql django annotations

在注释中我做了一些计算,我希望输出为小数,最多8位,最大2位小数。我不知道为什么但是Django会忽略decimal_places和max_digits。 这是我的代码:

Order.objects.all().annotate(
        amount=Coalesce(
            Sum(
                Case(
                    When(
                        Q(payments__status='complete'),
                        then=F('payments__amount') - (
                            F('payments__amount') * F('payments__vat')/100
                        ) 
                    ), output_field=DecimalField(decimal_places=2, max_digits=8)

                )
            ), 0)
    ).values('amount')

输出= 12.5999999999999996447286321199499070644378662109375 我正在使用Django 1.9.5

1 个答案:

答案 0 :(得分:3)

我在工作中遇到了同样的问题,为了解决这个问题,我创建了以下自定义聚合:

class SumDecimal(Func):
    function = 'SUM'
    name = 'sum'
    contains_aggregate = True
    output_field = DecimalField()
    template = '%(function)s(%(expressions)s)'

    def __init__(self, *args, **kwargs):
        self.decimal_places = kwargs.pop('decimal_places', None)
        super(SumDecimal, self).__init__(*args, **kwargs)

    def as_sql(self, compiler, connection, function=None, template=None):
        sql = super(SumDecimal, self).as_sql(
            compiler=compiler,
            connection=connection,
            function=function,
            template=template)

        if self.decimal_places:
            sql, params = sql
            sql = 'CAST(%s AS DECIMAL(16, %d))' % (sql, self.decimal_places)
            return sql, params

        return sql

要使用它非常简单,只需使用像这样:

mymodel.objects.all().annotate(sum_value=SumDecimal('value', decimal_places=2))