Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Object of type Decimal is not JSON serializable and convert to model data in views

rows = fetchall()
resultList = []
resultModel = []
resultDict = []
for row in rows:
    resultModel.append(ResultModel(*row)) # Object of type ResultModel is not JSON serializable
    resultList.append(list(row)) # Rows returned by pyodbc are not JSON serializable
    resultDict.append(dict(zip(columns, row))) # Object of type Decimal is not JSON serializable

I need to get a json version of the data in the view. For this, I am trying to get the JSON dump of the data. Using json.dumps(resultDict) throws the error.

The errors trying different results from the model is commented out for reference. The dict(zip()) option is the closest to what I want resultDict gives me a JSON (key, value) pairing that I can use. But it gives me an error on the resulting data that includes 'DecimalField' Is there a way to have decimal places without erroring on the data returned back? It seems that this would be a simple thing Django would support, so I'm not sure if I am missing something!

https://github.com/pyeve/eve-sqlalchemy/issues/50

Also, can I process the ResultModel directly into the json dump in the view, rather than setting up 2 result sets (of the same data, just different formatting) to send back to the view from the model?

UPDATE: I figured this out. As this is a stored proc/direct query, ORM mapping doesn't work when we use dict(zip(columns, row)) , the column names from the db query should be used. Then, for getting JSON do a json.dumps(myDict)

Alternate solution: In models, return [ResultModel(*row) for row in rows]

Views:

results = Get-model
json = serializers.serialize("python", results, fields=('Column1', 'Column2')

But this also gives me the model name. Is there a way to get only the .fields part of each list returned?

[ fields: {Column1: "1", Column2: "2"}, model:"app_name.resultmodel", pk:"" ]

like image 335
Loser Coder Avatar asked Dec 07 '22 13:12

Loser Coder


1 Answers

Try to extend the JSONEncoder

import json
from decimal import Decimal

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)

# Usage:
d = Decimal("42.5")
json.dumps(d, cls=DecimalEncoder)
like image 64
HP Bruna Avatar answered May 20 '23 14:05

HP Bruna