Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON: TypeError: Decimal('34.3') is not JSON serializable [duplicate]

Tags:

python

json

I am running an SQL query which returns a list of Decimals. When I try to convert this into JSON i get the type error.

The query:

res = db.execute("""
SELECT CAST ((SUM(r.SalesVolume)/1000.0) AS decimal(6,1))
FROM RawData r
INNER JOIN Product p
ON r.ProductId = p.ProductId 
INNER JOIN Calendar c
ON r.DayId = c.DayId
WHERE c.WeekCodeInYear BETWEEN 1 AND 12
AND 
c.YearId = 2014
GROUP BY c.WeekCodeInYear """)

Result List:

[Decimal('34.3'), Decimal('50.9'), Decimal('31.5'), Decimal('23.3'), Decimal('19
.7'), Decimal('56.9'), Decimal('43.8'), Decimal('35.2'), Decimal('29.2'), Decima
l('43.7'), Decimal('42.6'), Decimal('23.4')]

Code:

for row in res:
    testlist.append (row[0])
    print testlist

list = json.dumps(testlist)

And the I get the Unable to serialize error Tried looking up online, no much help. Please note that the final list would go as input data to a chart.

like image 320
Tauseef Hussain Avatar asked Jul 03 '15 09:07

Tauseef Hussain


2 Answers

Use a override default:

import json
from decimal import Decimal

def default(obj):
    if isinstance(obj, Decimal):
        return str(obj)
    raise TypeError("Object of type '%s' is not JSON serializable" % type(obj).__name__)

json.dumps(testlist, default=default)

Or just do str on Decimal object:

for row in res:
    testlist.append (str(row[0]))
json.dumps(testlist)
like image 129
LittleQ Avatar answered Nov 13 '22 23:11

LittleQ


As the error says, the Decimal type is not able to be serialized directly into JSON. Considering casting the Decimal into a float if you wish to keep that as a number, however you may get rounding errors. i.e.

for row in res:
    testlist.append(float(row[0]))

Or alternatively build the list using list comprehension, this time I cast to str.

testlist = [str(row[0]) for row in res]

The latter is an appropriate representation as the Decimal type can be unambiguously represented by str. You can grab the original value like so

from decimal import Decimal
jlist = json.dumps(testlist)  # don't use list as it's predefined type
new_list = json.loads(jlist)
new_dlist = [Decimal(s) for s in new_list]

new_dlist should be identical to the original templist.

like image 45
metatoaster Avatar answered Nov 14 '22 01:11

metatoaster