Django:请求值时从查询集注释字段中删除十进制前缀
Django: remove Decimal prefix from queryset annotated field, when requesting values
简而言之,我有这个查询集:
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()
前缀。
感谢任何帮助或提示。
你可以把它转换成 float 类型,像这样
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=float(Sum('price')))
.order_by('month'))
由于您使用的是 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)
我终于找到了两个适合我的解决方案:
感谢 @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}]
希望这对以后的任何人都有帮助。
如果您只想删除 "Decimal" 前缀,您可以在注释中定义一个特定的输出字段:
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=Sum('price', output_field=FloatField()))
.order_by('month'))
简而言之,我有这个查询集:
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()
前缀。
感谢任何帮助或提示。
你可以把它转换成 float 类型,像这样
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=float(Sum('price')))
.order_by('month'))
由于您使用的是 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)
我终于找到了两个适合我的解决方案:
感谢 @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}]
希望这对以后的任何人都有帮助。
如果您只想删除 "Decimal" 前缀,您可以在注释中定义一个特定的输出字段:
monthly_revenue = list(Booking.objects.annotate(month=Month('created_at'))
.values('month')
.annotate(total=Sum('price', output_field=FloatField()))
.order_by('month'))