Django:在请求值时从查询集注释字段中删除小数前缀
Posted
技术标签:
【中文标题】Django:在请求值时从查询集注释字段中删除小数前缀【英文标题】:Django: remove Decimal prefix from queryset annotated field, when requesting values 【发布时间】:2020-05-04 06:24:57 【问题描述】:简而言之,我有这个查询集:
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=Sum('price'))
.order_by('month'))
这是它返回的内容:
['month': 11, 'total': Decimal('4550.00')]
结果将转到 js 脚本以显示图形,我需要删除 Decimal()
前缀。
任何帮助或提示表示赞赏。
【问题讨论】:
【参考方案1】:如果您只想删除“十进制”前缀,您可以在注释中定义一个特定的输出字段:
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=Sum('price', output_field=FloatField()))
.order_by('month'))
【讨论】:
【参考方案2】:由于您使用的是Django
,因此您可以使用DjangoJSONEncoder
,如下所示:
from django.core.serializers.json import DjangoJSONEncoder
my_dict = ['month': 11, 'total': Decimal('4550.00')]
json_result = json.dumps(my_dict, cls=DjangoJSONEncoder)
但是,请记住,DjangoJSONEncoder
会将十进制转换为字符串,因此结果将是:
["month": 11, "total": "4550.00"]
如果您导航到 DjangoJSONEncoder
源代码,您会发现:
elif isinstance(o, (decimal.Decimal, uuid.UUID, Promise)):
return str(o)
【讨论】:
我已经为模型序列化扩展了该编码器,现在我只是将其调整为将十进制转换为浮点数,我将分享解决方案。【参考方案3】:你可以把它转换成浮点型,像这样
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=float(Sum('price')))
.order_by('month'))
【讨论】:
我早些时候尝试过,它不起作用它抛出:Traceback (most recent call last): File "<input>", line 3, in <module> TypeError: float() argument must be a string or a number, not 'Sum'
您可以在调用 Sum 函数之前将其转换为浮点数
不能在查询float() argument must be a string or a number, not 'F'
中使用float
【参考方案4】:
我终于找到了两个对我有用的解决方案:
感谢@Ramy 的回答,我覆盖了DjangoJSONEncoder
,以支持将小数转换为浮点数:
import decimal
import uuid
from django.utils.functional import Promise
from django.core.serializers.json import DjangoJSONEncoder
class JsonDecimalToFloatEncoder(DjangoJSONEncoder):
def default(self, o):
if isinstance(o, (decimal.Decimal, uuid.UUID, Promise)):
return float(o)
return super().default(o)
我按照他所说的那样使用它:
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=Sum('price'))
.order_by('month'))
json_result = json.dumps(monthly_revenue,cls=ExtendedEncoder)
json_result
'["month": 11, "total": 4550.0]'
这个解决方案需要在服务器端做更多的工作,所以我选择了@rossi 的第二个解决方案,它在数据库而不是服务器上做更多的工作,这就是 django 的文档所建议的。
from django.db.models import FloatField
from django.db.models.functions import Cast
list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total_as_f=Cast('total',
output_field=FloatField()))
.order_by('month'))
['month': 11, 'total': Decimal('4550.00'), 'total_as_f': 4550.0]
希望这对未来的任何人都有帮助。
【讨论】:
以上是关于Django:在请求值时从查询集注释字段中删除小数前缀的主要内容,如果未能解决你的问题,请参考以下文章