AVG Decimal simplejson (Decimal is not JSON serializable)
Posted: May 26th, 2010 | Author: ekaterina | Filed under: Django | Tags: Decimalisnotjsonseriazable | 4 Comments »If you use AVG aggregation function on Integer field in MySQL,
hotels = Hotel.objects.filter(city = "Paris").extra(
select={
'avg_rate': 'SELECT AVG(hotel_review.rate) FROM hotel_review WHERE hotel_review.is_active = 1 AND hotel_review.hotel_id = hotel_hotel.id',
},
)
you will have in a result { “avg_rate” : Decimal(’2.6667′)} and an “Exception Value: Decimal(’2.6667′) is not JSON serializable”.
In this case you can do this:
from django.utils import simplejson
from decimal import Decimal
class MyJSONEncoder(simplejson.JSONEncoder):
"""JSON encoder which understands decimals."""
def default(self, obj):
'''Convert object to JSON encodable type.'''
if isinstance(obj, Decimal):
return "%d" % obj
return simplejson.JSONEncoder.default(self, obj)
hotels_json = simplejson.dumps(list(hotels.values()), cls = MyJSONEncoder)
You can read about extra search fields and JSON serialization in our article

Nice simple trick for this Decimal problem I’m facing too
thanks, that’s much simplier than recoding an entire json serializer
This solution truncates the decimal to and int value. It would not give a very good answer unless you actually mean to call floor() on your decimal value.
A better solution would be to replace line 10:
return “%d” % obj
with
return obj.to_eng_string()
this way you still get a stringified version of your decimal, without rounding errors or forcing it to an integer.
Also, since simplejson 2.1.0, you can pass ‘use_decimal=True’ to simplejson.dumps(), which will handle this for you without needing to add this handler.
django.utils, though, has 2.0.7 as of 1.2 , so this technique is still useful.
Thanks mate!
For simplejson 2.1 and above the use_decimal parameter is available.
hotels_json = simplejson.dumps(list(hotels.values()), use_decimal=True)
This converts the decimal to a float I think.