【问题标题】:Django annotation output_field=DecimalField ignores max_digits and decimal_placesDjango 注释 output_field=DecimalField 忽略 max_digits 和 decimal_places
【发布时间】:2017-07-04 01:49:06
【问题描述】:

在注释中我做了一些计算,我希望输出为小数,最多 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

【问题讨论】:

  • 尝试使用output_fieldarg最外层函数,即Coalesce或尝试使用Cast
  • 在最外层 - 不工作。 Cast - 来自 Django 1.10,在 1.9.5 中不存在,我会尝试升级到 1.10.5
  • @Todor 我升级到 1.10.5,我的应用程序的一半已关闭,但是当我使用 Cast 时,我得到 "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'numeric(None, None)) AS `amount` FROM `order` LEFT OUTER JOIN `' at line 1" 使用 1.10 对我没有任何作用,任何解决方法在 1.9.5 中?我将等待 LTS 的 1.11 stable 升级

标签: mysql django annotations


【解决方案1】:

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

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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 2018-04-16
    • 2015-09-06
    • 2012-09-09
    • 2016-05-22
    • 1970-01-01
    • 2021-05-11
    • 2011-11-13
    相关资源
    最近更新 更多