[Fixed]-Django annotation output_field=DecimalField ignores max_digits and decimal_places

5๐Ÿ‘

โœ…

I had had the same issue in my job, to solve this Iโ€™ve created the following custom aggregate:

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

To use this is pretty simple, just use like:

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

Leave a comment