0

我有一个带有一些财务数据的 JSONField。我不能将它存储为浮点数,因为我需要精度,所以我将它存储为字符串。

我的模型看起来像这样

class Finance(models.Model)
    bill_data = JSONField(
        verbose_name=_("Bill data"),
        default=dict,
        blank=True,
    )

然后我保存

bill_data = dict(paid=str(some_decimal_amount))

Finance.objects.create(bill_data=bill_data)

我尝试使用Cast将其转换回十进制,因为我需要使用表达式,

Finance.objects.all().annotate(paid=Cast('bill_data__paid', DecimalField()))

我收到一个错误

    return self.cursor.execute(sql, params)
django.db.utils.DataError: invalid input syntax for integer: "none"
LINE 1: ...der"."bill_data", ("myapp_finance"."bill_data")::numeric(No...

有谁知道如何在表达式中使用fromstrJSONField如何正确处理?DecimalJSONField

4

1 回答 1

2

所以今天我为此苦苦挣扎。在帮助下,我们设法让它工作。

from django.db.models.functions import Cast
from django.db.models.fields.json import KeyTextTransform
from django.db.models import JSONField, DecimalField

from django.db import models


class Finance(models.Model):
    bill_data = JSONField(
        verbose_name="Bill data",
        default=dict,
        blank=True,
    )

好的,首先我假设 bill_data__paid 在任何地方都不是 Null 。如果是,您应该首先执行以下操作:

Finance.objects.filter(bill_data__paid__isnull=False)

以确保您没有强制转换任何 Null 字段。

好的,那么让我们试试你做了什么:

Finance.objects.annotate(
    paid=Cast("bill_data__paid", output_field=DecimalField()),
)

但是我们得到一个错误,类似于:

整数类型的无效输入语法:“none” 第 1 行:# ...("myapp_finance"."bill_data" -> 'paid') AS numeric(No......

好吧,这不是很好。那我们现在能做什么呢?好吧,也许我们需要指定 Decimal 字段的小数位数和最大位数,我们这样做是对的。

Finance.objects.annotate(
    paid=Cast("bill_data__paid", output_field=DecimalField(max_digits=6, decimal_places=2)),
)

但这行得通吗?可悲的是没有。我们现在收到错误

无法将 jsonb 字符串转换为数字类型

嗯好的。不是很好,但至少这是一个不同的错误。问题是我们有一个 jsonb 字符串。让我们把它变成一个文本字符串(因为缺乏更好的描述)

Finance.objects.annotate(
    paid=Cast(KeyTextTransform("paid", "bill_data"), output_field=DecimalField(max_digits=6, decimal_places=2))
)

现在,它将起作用。

因此,我们将 jsonb 字符串转换为文本,然后将其转换为十进制(您必须指定小数位数和最大位数)。

结束 :)

于 2021-11-18T21:08:32.980 回答