Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I configure Pyramid's JSON encoding?

I'm trying to return a function like this:

@view_config(route_name='CreateNewAccount', request_method='GET', renderer='json')
def returnJSON(color, message=None):
    return  json.dumps({ "color" : "color", "message" : "message" }, default=json_util.default)

Because of Pyramid's own JSON encoding, it's coming out double-encoded like this:

"{\"color\": \"color\", \"message\": \"message\"}"

How can I fix this? I need to use the default argument (or equivalent) because it's required for Mongo's custom types.

like image 621
zakdances Avatar asked Jun 04 '12 19:06

zakdances


3 Answers

It seems like the dictionary is being JSON-encoded twice, the equivalent of:

json.dumps(json.dumps({ "color" : "color", "message" : "message" }))

Perhaps your Python framework automatically JSON-encodes the result? Try this instead:

def returnJSON(color, message=None):
  return { "color" : "color", "message" : "message" }

EDIT:

To use a custom Pyramid renderer that generates JSON the way you want, try this (based on the renderer docs and the renderer sources).

In startup:

from pyramid.config import Configurator
from pyramid.renderers import JSON

config = Configurator()
config.add_renderer('json_with_custom_default', JSON(default=json_util.default))

Then you have a 'json_with_custom_default' renderer to use:

@view_config(route_name='CreateNewAccount', request_method='GET', renderer='json_with_custom_default')

EDIT 2

Another option could be to return a Response object which he renderer shouldn't modify. E.g.

from pyramid.response import Response
def returnJSON(color, message):
  json_string = json.dumps({"color": color, "message": message}, default=json_util.default)
  return Response(json_string)
like image 97
orip Avatar answered Oct 16 '22 12:10

orip


In addition to other excellent answers, I'd like to point out that if you don't want the data returned by your view function to be passed through json.dumps then you should not use renderer="json" in the view configuration :)

So instead of

@view_config(route_name='CreateNewAccount', request_method='GET', renderer='json')
def returnJSON(color, message=None):
    return  json.dumps({ "color" : "color", "message" : "message" }, default=json_util.default)

you can just use

@view_config(route_name='CreateNewAccount', request_method='GET', renderer='string')
def returnJSON(color, message=None):
    return  json.dumps({ "color" : "color", "message" : "message" }, default=json_util.default)

string renderer will just pass the string data returned by your function as-is. However, registering a custom renderer is a nicer approach (see @orip's answer)

like image 26
Sergey Avatar answered Oct 16 '22 12:10

Sergey


You didn't say, but I will assume you are just using the standard json module.

The json module doesn't define a class for JSON; it uses a standard Python dict as the "native" representation of your data. json.dumps() encodes a dict as a JSON string; json.loads() takes a JSON string and gives back a dict.

So instead of doing this:

def returnJSON(color, message=None):
    return  json.dumps({ "color" : "color", "message" : "message" }, default=json_util.default)

Try doing this:

def returnJSON(color, message=None):
    return { "color" : "color", "message" : "message" }

Just pass back a plain dict. See how your iPhone app likes this.

like image 1
steveha Avatar answered Oct 16 '22 12:10

steveha