简体   繁体   中英

Confused by Python returning JSON as string instead of literal

I've done some coding in RoR, and in Rails, when I return a JSON object via an API call, it returns as

{ "id" : "1", "name" : "Dan" } .

However in Python (with Flask and Flask-SQLAlchemy), when I return a JSON object via json.dumps or jsonpickle.encode it is returned as

"{ \\"id\\" : \\"1\\", \\"name\\": \\"Dan\\" }" which seems very unwieldily as it can't easily be parsed on the other end (by an iOS app in this case - Obj-C).

What am I missing here, and what should I do to return it as a JSON literal, rather than a JSON string?

This is what my code looks like:

people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)

json_object = jsonpickle.encode(friends.first().as_dict(), unpicklable=False, keys=True)
print(json_object)  # this prints here, i.e. { "id" : "1", "name" : "Dan" }

return json_object # this returns "{ \"id\" : \"1\", \"name\": \"Dan\" }" to the browser

Looks like you are using Django here, in which case do something like

from django.utils import simplejson as json
...
return HttpResponse(json.dumps(friends.first().as_dict()))

What is missing in your understanding here is that when you use the JSON modules in Python, you're not working with a JSON object. JSON is by definition just a string that matches a certain standard.

Lets say you have the string:

friends = '{"name": "Fred", "id": 1}'

If you want to work with this data in python, you will want to load it into a python object:

import json
friends_obj = json.loads(friends)

At this point friends_obj is a python dictionary.

If you want to convert it (or any other python dictionary or list) then this is where json.dumps comes in handy:

friends_str = json.dumps(friends_obj)
print friends_str
'{"name": "Fred", "id": 1}'

However if we attempt to "dump" the original friends string you'll see you get a different result:

dumped_str = json.dumps(friends)
print dumped_str
'"{\\"name\\": \\"Fred\\", \\"id\\": 1}"'

This is because you're basically attempting to encode an ordinary string as JSON and it is escaping the characters. I hope this helps make sense of things!

Cheers

This is almost always a sign that you're double-encoding your data somewhere. For example:

>>> obj = { "id" : "1", "name" : "Dan" }
>>> j = json.dumps(obj)
>>> jj = json.dumps(j)
>>> print(obj)
{'id': '1', 'name': 'Dan'}
>>> print(j)
{"id": "1", "name": "Dan"}
>>> print(jj)
"{\"id\": \"1\", \"name\": \"Dan\"}"

Here, jj is a perfectly valid JSON string representation—but it's not a representation of obj , it's a representation of the string j , which is useless.

Normally you don't do this directly; instead, either you started with a JSON string rather than an object in the first place (eg, you got it from a client request or from a text file), or you called some function in a library like requests or jsonpickle that implicitly calls json.dumps with an already-encoded string. But either way, it's the same problem, with the same solution: Just don't double-encode.

You should be using flask.jsonify , which will not only encode correctly, but also set the content-type headers accordingly.

people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)

return jsonify(friends.first().as_dict())

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