我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
我有一个十进制('3.9')作为对象的一部分,并希望将其编码为一个JSON字符串,它应该看起来像{'x': 3.9}。我不关心客户端的精度,所以浮点数很好。
有什么好方法来序列化它吗?JSONDecoder不接受Decimal对象,提前转换为浮点数会产生{'x': 3.8999999999999999},这是错误的,而且会浪费大量带宽。
当前回答
对于任何想要快速解决的人来说,这里是我如何从Django中的查询中删除Decimal的
total_development_cost_var = process_assumption_objects.values('total_development_cost').aggregate(sum_dev = Sum('total_development_cost', output_field=FloatField()))
total_development_cost_var = list(total_development_cost_var.values())
步骤1:使用,output_field=FloatField()在你的查询 步骤2:使用列表eg list(total_development_cost_var.values())
希望能有所帮助
其他回答
您可以根据需要创建一个自定义JSON编码器。
import json
from datetime import datetime, date
from time import time, struct_time, mktime
import decimal
class CustomJSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return str(o)
if isinstance(o, date):
return str(o)
if isinstance(o, decimal.Decimal):
return float(o)
if isinstance(o, struct_time):
return datetime.fromtimestamp(mktime(o))
# Any other serializer if needed
return super(CustomJSONEncoder, self).default(o)
解码器可以这样命名,
import json
from decimal import Decimal
json.dumps({'x': Decimal('3.9')}, cls=CustomJSONEncoder)
输出将是:
>>'{"x": 3.9}'
对于那些不想使用第三方库的人…Elias Zamaria的答案的一个问题是,它转换为浮动,这可能会遇到问题。例如:
>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 1e-07}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01733}'
JSONEncoder.encode()方法允许您返回json文本内容,这与JSONEncoder.default()不同,后者让您返回一个json兼容类型(如float),然后以正常方式进行编码。encode()的问题是它(通常)只在顶层工作。但它仍然可用,只需要做一些额外的工作(python 3.x):
import json
from collections.abc import Mapping, Iterable
from decimal import Decimal
class DecimalEncoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, Mapping):
return '{' + ', '.join(f'{self.encode(k)}: {self.encode(v)}' for (k, v) in obj.items()) + '}'
if isinstance(obj, Iterable) and (not isinstance(obj, str)):
return '[' + ', '.join(map(self.encode, obj)) + ']'
if isinstance(obj, Decimal):
return f'{obj.normalize():f}' # using normalize() gets rid of trailing 0s, using ':f' prevents scientific notation
return super().encode(obj)
这就给了你:
>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 0.0000001}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01734}'
原生Django选项缺失了,所以我将为下一个寻找它的guy/gall添加它。
从Django 1.7开始。x中有一个内置的DjangoJSONEncoder,你可以从django.core. serialzers .json中获取。
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict
model_instance = YourModel.object.first()
model_dict = model_to_dict(model_instance)
json.dumps(model_dict, cls=DjangoJSONEncoder)
很快!
十进制不适合通过以下方式进行转换:
浮子由于精度问题 由于openapi的限制
我们仍然需要直接十进制到一个数字json序列化。
下面是@tesdal的fakfloat解决方案的扩展(在v3.5.2rc1中关闭)。 它使用fakestr + monkeypatching来避免引号和小数的“浮动”。
import json.encoder
from decimal import Decimal
def encode_fakestr(func):
def wrap(s):
if isinstance(s, fakestr):
return repr(s)
return func(s)
return wrap
json.encoder.encode_basestring = encode_fakestr(json.encoder.encode_basestring)
json.encoder.encode_basestring_ascii = encode_fakestr(json.encoder.encode_basestring_ascii)
class fakestr(str):
def __init__(self, value):
self._value = value
def __repr__(self):
return str(self._value)
class DecimalJsonEncoder(json.encoder.JSONEncoder):
def default(self, o):
if isinstance(o, Decimal):
return fakestr(o)
return super().default(o)
json.dumps([Decimal('1.1')], cls=DecimalJsonEncoder)
[1.1]
我不明白为什么python开发人员强迫我们在不适合使用浮点数的地方使用浮点数。
我想让每个人都知道,我在运行Python 2.6.5的网络服务器上尝试了michaowarmarczyk的答案,它工作得很好。然而,我升级到Python 2.7,它停止工作了。我试着想一些方法来编码十进制对象,这就是我想到的:
import decimal
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
注意,这将把小数转换为它的字符串表示形式(例如;“1.2300”),以a.不丢失有效数字和b.防止舍入错误。
希望这能帮助任何在使用Python 2.7时遇到问题的人。我测试过了,它似乎工作得很好。如果有人在我的解决方案中注意到任何错误或提出了更好的方法,请告诉我。
使用的例子:
json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)