Search code examples
pythonjsonpyramidmongoengine

Python Pyramid not rendering JSON correctly


I am using MongoEngine's to_json method on an object I wish to render in a json-rendered Pyarmid page. I've done lots of json rendering in Pyramid, but not with MongoEngine. MongoEngine's to_json method simple calls json_util.dumps. It all works fine in Python. The problem is that when Pyramid renders the page, it is rendered like this:

{
  "0": "\"",
  "1": "{",
  "2": "\\",
  "3": "\"",
  "4": "_",  etc...

However, the json dump looks ok in Python, before it is rendered:

'{"_id": {"$oid": "4ebca43ccc7a67085b000000"}, "created": {"$date": 1346419407715}, "modified": {"$date": 1403757381829}, "modified_by": {"$oid": "4ebca43ccc7a67085b000000"}, "email":  etc...

As has been suggested in the comments, it seems like the json is being jsonified more than once, but I can't figure out where.

I pick up the User object from the database and attach it every request:

def get_user(request):
    return User.objects(id=ObjectId(authenticated_userid(request))).first()

config.add_request_method(get_user, 'user', reify=True)

I return the user as per request:

@view_config(route_name='api.user', permission='authenticated', renderer='json')
def user_vc(request):
    response = request.response
    _id = request.matchdict['id']
    if _id == 'session':
        user = request.user
        if not user:
            response.status = 403
            return response
        else:
            print user  # user object as expected (not json)
            return user

I have a custom adapter to handle the User object:

# custom json adapters
custom_json = JSON()

def user_adapter(obj, request):
    print obj.to_json()  # the json looks ok here
    return obj.to_json()
custom_json.add_adapter(User, user_adapter)

config.add_renderer('json', custom_json)

I am not doing any other jsonification myself, apart from the adapter above. So what is?? Any help would be great.


Solution

  • Thanks to a comment by @AnttiHappala above, I found the problem. MongoEngine's to_json method converts objects to a jsonified string. However, Pyramid needs a json data structure. So, to fix it, I added the following function to my custom renderer:

    def render_to_json(obj):
            return json.loads(obj.to_json())
    
        def user_adapter(obj, request):
            return render_to_json(obj)
        custom_json.add_adapter(User, user_adapter)
    

    I can now add a custom renderer for my other MongoEngine objects and return them natively.