Getting 'TypeError: ObjectId('') is not JSON serializable' when using Flask 0.10.1

烈酒焚心 提交于 2019-12-20 10:24:07

问题


I forked the Flask example, Minitwit, to work with MongoDB and it was working fine on Flask 0.9, but after upgrading to 0.10.1 I get the error in title when I login when I try to set the session id.

It seems there was changes in Flask 0.10.1 related to json.

Code snippet:

user = db.minitwit.user.find_one({'username': request.form['username']})
session['_id'] = user['_id']

Full code in my github repo.

Basically, I set the Flask session id to the user's _id from MongoDB.

I tried the first two solution from this SO question without success.

Well, doing session['_id'] = str(user['_id']) gets rid of the error message and I'm properly redirected to the timeline page but I am not actually logged in.

How can I fix this?

EDIT: Copy/paste of the traceback: http://pastebin.com/qa0AL1fk

Thank you.


回答1:


EDIT: Even easier fix. You don't even need to do any JSON encoding/decoding.

Just save the session['_id'] as a string:

user = db.minitwit.user.find_one({'username': request.form['username']})
session['_id'] = str(user['_id'])

And then everywhere you want to do something with the session['_id'] you have to wrap it with ObjectId() so it's passed as a ObjectId object to MongoDB.

if '_id' in session:
    g.user = db.minitwit.user.find_one({'_id': session['_id']})

to:

if '_id' in session:
    g.user = db.minitwit.user.find_one({'_id': ObjectId(session['_id'])})

You can see the full diff for the fix on my github repo.

If anyone cares to know why the 'TypeError: ObjectId('') is not JSON serializable' "issue" appeared in Flask 0.10.1, it's because they changed the way sessions are stored. They are now stored as JSON so since the '_id' object in MongoDB isn't standard JSON, it failed to serialize the session token, thus giving the TypeError. Read about the change here: http://flask.pocoo.org/docs/upgrading/#upgrading-to-010




回答2:


JSON only supports serializing (encoding/decoding) a limited set of objects types by default. You could extend python JSON's decoder/encoder's to handle this situation though.

In terms of encoding an object which contains on ObjectID, for example, when ObjectIds are created client side, which will be passed along to some awaiting server, try:

import json
from bson.objectid import ObjectId

class Encoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, ObjectId):
            return str(obj)
        else:
            return obj

Then, in your code, before pushing the data client -> server, run:

json.dumps(obj, cls=Encoder)

Server side, if we know we're dealing with mongo docs, (dictionary object with an '_id' key), we can define a json decoder hook like the following:

def decoder(dct):
    for k, v in dct.items():
        if '_id' in dct:
            try:
                dct['_id'] = ObjectId(dct['_id'])
            except:
                pass
        return dct

And call it using a call like the following:

doc = json.loads(in_doc, object_hook=decoder)

You'll probably need to adapt this code a bit, but for the simple case of passing




回答3:


This is how I've recently fixed the error

@app.route('/')
def home():
    docs = []
    for doc in db.person.find():
        doc.pop('_id') 
        docs.append(doc)
    return jsonify(docs)



回答4:


toString converts it to the string and that can stored to session:

session['_id'] = user['_id'].toString()

alternative session['_id'] = str(user['_id'])

The above fixed the error for me.



来源:https://stackoverflow.com/questions/17635015/getting-typeerror-objectid-is-not-json-serializable-when-using-flask-0-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!