Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with Decimal to Json in requests library

I'm trying to send post data to an api which needs to be in json. If the requests header doesn't have Content-type: application-json the request fails and I get an HTTPError: 415 Client Error: Unsupported Media Type for url

However requests only seems to add in this header if I use the inbuilt json parser. Even though the docs seem to suggest the below is equivalent:

>>> r = requests.post(url, data=json.dumps(payload))

>>> r = requests.post(url, json=payload)

Which means that I need to use the built in json parser (or manually add the Content-type header).

However my post data has several Decimal fields (from api converted via json.loads(response.text, parse_float=decimal.Decimal) to be saved in a django DecimalField) which when using the inbuilt requests parser gives the error:

TypeError: Decimal('1560.35') is not JSON serialisable

Is there a way I can use a different json parser with requests (e.g. simplejson which deals with decimals) and have the content-type still specified.

like image 606
Yunti Avatar asked Sep 11 '25 09:09

Yunti


2 Answers

Just install simplejson and requests will use it to serialize Decimals:

$ pip3 install simplejson    

This won't raise a TypeError anymore:

>>> requests.post(url, json={'foo': Decimal('1.23')})
like image 180
Max Malysh Avatar answered Sep 13 '25 23:09

Max Malysh


Decimals can be serialized by passing through a custom function.

def decimal_default(obj):
    if isinstance(obj, Decimal):
        return str(obj)
    raise TypeError


data = json.dumps(payload, default=decimal_default)

response = requests.post(
    url=url,
    data=data,
    headers={
        'Content-type': 'application/json',
    }
)
like image 44
pymarco Avatar answered Sep 13 '25 23:09

pymarco