简体   繁体   中英

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.

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. Eg

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)

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)

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.

You are dumping the string of the Python object (dictionary) you are giving it.

The manual for json.dumps states:

Serialize obj to a JSON formatted str.

To convert back from the string, you will need to use the Python JSON function loads which LOADS a string into a JSON object.

What it appears you are trying to do however, is encode a python dictionary to JSON.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM