Yunti
Yunti

Reputation: 7438

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.

Upvotes: 4

Views: 4354

Answers (3)

Max Malysh
Max Malysh

Reputation: 31545

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')})

Upvotes: 4

pymarco
pymarco

Reputation: 8195

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',
    }
)

Upvotes: 2

salomonderossi
salomonderossi

Reputation: 2188

I do not know how to use a different json parser, but you can set the header (and so the content-type).

r = requests.post(url, data=json.dumps(payload), headers={'Content-type': 'application/json'})
# or with a session object
s = requests.Session()
s.headers['Content-Type'] = 'application/json'
s.post(url, data=json.dumps(payload))

Upvotes: 1

Related Questions